如何在 Spring Security 过滤器中授权 CORS

Posted

技术标签:

【中文标题】如何在 Spring Security 过滤器中授权 CORS【英文标题】:How to authorize CORS in Spring Security filter 【发布时间】:2021-10-28 03:15:52 【问题描述】:

我正在尝试使用 Spring Boot 和 Spring Security 构建一个 REST API,但我遇到了一个问题,即对 /login 端点的任何请求由于 CORS 而被阻止,我不知道如何允许它。

每当我在前端应用程序中发送登录请求时检查开发工具的网络选项卡时,我会得到以下结果:

这是我的SecurityConfig.java 文件(为简洁起见,我省略了导入):

@EnableWebSecurity(debug = true)
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter 
    private final AuthenticationUserDetailService authenticationUserDetailService;
    private final PasswordEncoder passwordEncoder;
    @Value("$jwt.secret")
    private String jwtSecret;

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.csrf().disable();
        http.cors();
        http.authorizeRequests().antMatchers("/login").permitAll();
        http.authorizeRequests().antMatchers("/").permitAll();
        http.authorizeRequests().antMatchers("/api/teachers/**").hasAuthority("TEACHER");
        http.authorizeRequests().antMatchers("/api/students/**").hasAuthority("STUDENT");
        http.authorizeRequests().antMatchers("/api/**").hasAuthority("ADMIN");

        http.authorizeRequests().anyRequest().authenticated();
        //http.authorizeRequests().anyRequest().permitAll();
        http.addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtSecret));
        http.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtSecret));
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(authenticationUserDetailService).passwordEncoder(passwordEncoder);
    

这是我的JwtAuthenticationFilter.java 文件:

public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter 
    private final AuthenticationManager authenticationManager;
    private final String jwtSecret;

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, String jwtSecret) 
        this.authenticationManager = authenticationManager;
        this.jwtSecret = jwtSecret;
        setFilterProcessesUrl("/login");
    

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException 
        try 
            LoginRequest credentials = new ObjectMapper()
                    .readValue(request.getInputStream(), LoginRequest.class);

            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            credentials.getUsername(),
                            credentials.getPassword(),
                            new ArrayList<>())
            );
         catch (IOException e) 
            throw new RuntimeException(e);
        
    

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException 
        User user = (User) authResult.getPrincipal();

        String token = Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, jwtSecret.getBytes())
                .claim("role", authResult.getAuthorities().iterator().next().getAuthority())
                .setSubject(user.getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + 24 * 3600 * 1000))
                .compact();

        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write("\"token\":\"" + token + "\"");
    

我已经尝试了我在网上找到的所有解决方案,但我没有想法。如何从任何来源为我的 /login 端点授权 CORS?

非常感谢!

【问题讨论】:

你能发布你的登录控制器吗?这里有2个问题。 1.您面临的 CORS 问题,因为您的 UI 在实际 POST 调用之前进行了 OPTIONS 调用。 2. 403 理想情况下不应该存在,因为您在 ant matcher 中排除了 /login。所以只想交叉检查 @SridharPatnaik 我没有登录控制器。一切都在 JwtAuthenticationFilter 类中。 这能回答你的问题吗? How to configure CORS in a Spring Boot + Spring Security application? CORS 是 Spring Security 中回答最多的问题。我们每周收到大约 5 个关于它的问题。提问前请使用搜索功能。 Spring 安全文档有一整章是关于 CORS 的,这里有 100 多个关于 CORS 的答案。投票关闭重复。 【参考方案1】:

您必须提供CorsConfigurationSource 类型的 Bean,并告诉 Spring Security 在 CorsFilter 中使用该配置源,并将其放在身份验证和授权过滤器之前。

首先,定义CorsConfigurationSource Bean:

@Bean
CorsConfigurationSource corsConfigurationSource() 
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    config.addAllowedOrigin("http://localhost:3000");
    source.registerCorsConfiguration("/**", config);
    return source;

然后,告诉 Spring Security 使用默认值配置 CORS:

@Override
protected void configure(HttpSecurity http) throws Exception 
    ...
    http.cors(Customizer.withDefaults());
    ...

【讨论】:

以上是关于如何在 Spring Security 过滤器中授权 CORS的主要内容,如果未能解决你的问题,请参考以下文章

如何避免自定义过滤器在spring-security中为不安全的url运行

如何在 Spring Security 过滤器中授权 CORS

如何使用带有多个过滤器和 Spring Security 的 Spring DelegatingFilterProxy?

如何使用 Spring Security 为微服务创建自定义安全过滤器

如何使用 Spring Session + Spring security xml 配置和多重安全过滤器

如何仅针对特定 url 添加 Spring Security 验证码过滤器