允许使用带有经过身份验证的请求的 Spring Security 6.1.1 进行 CORS

use*_*270 6 spring-security cors spring-boot

我已经从 Spring Boot 2.5 升级到 3.1,它附带了 Spring Security 6.1.1。对登录身份验证 REST 服务的调用工作正常,但对需要身份验证令牌的其他 REST 控制器的所有请求都被 CORS 策略阻止。

我已按照 Springs 文档中的说明禁用 CORS,但它不起作用。 https://docs.spring.io/spring-security/reference/reactive/integrations/cors.html#page-title

这是我当前的配置:

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOriginPattern("*");
        configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","PATCH","DELETE","OPTIONS"));
        configuration.setAllowCredentials(false);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                //.cors(cors -> cors.disable()) <<--- does not work as documented
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(request -> request
                    .requestMatchers("/api/auth/**").permitAll()
                    .requestMatchers(SYS_ADMIN_PATTERNS).hasAuthority("SYSTEM_ADMIN")
                    .requestMatchers("/api/v1/**").authenticated()
            )
            .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
            .authenticationProvider(authenticationProvider())
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
Run Code Online (Sandbox Code Playgroud)

我尝试使用 .cors(cors -> cors.disable()) 设置禁用 CORS,但这并没有禁用 CORS 过滤。

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(cors -> cors.disable()) 
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(request -> request
                    .requestMatchers("/api/auth/**").permitAll()
                    .requestMatchers(SYS_ADMIN_PATTERNS).hasAuthority("SYSTEM_ADMIN")
                    .requestMatchers("/api/v1/**").authenticated()
            )
            .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
            .authenticationProvider(authenticationProvider())
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        return http.build();
    }
Run Code Online (Sandbox Code Playgroud)

还尝试将 @CrossOrigin 注释标记添加到 REST 控制器类,但什么也没做。还验证了我是否具有 @Configuration 注释和 @EnableWebSecurity 注释(Spring Security 中的另一个更改)。

我缺少什么?

Anm*_*hah 10

经过几天的努力,我得出了一些结论,比如这是如何运作的。

我在预检请求中遇到 401 错误

我遵循了文档代码,因为预检请求导致了问题,我又添加了一个专门针对预检请求的 requestMather

 .requestMatchers(HttpMethod.OPTIONS,"/**").permitAll()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

并将 @CrossOrigin 添加到类级别的控制器中


use*_*270 3

我可以让它工作的唯一方法是在 SecurityFilterChain 中禁用 CORS 并使用 @CrossOrigin 注释 RestController。如果您配置了 CorsConfigurationSource,则 @CrossOrigin 注释将被忽略(或至少没有效果),并且它根本无法与 Spring Security 6.1 一起使用。

这是工作配置:

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .cors(AbstractHttpConfigurer::disable)
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(request -> request
                    .requestMatchers("/api/auth").permitAll()
                    .requestMatchers(HttpMethod.OPTIONS).permitAll()
                    .requestMatchers(SYS_ADMIN_PATTERNS).hasAuthority("SYSTEM_ADMIN")
                    .requestMatchers("/api/v1/**").authenticated()
            )
            .sessionManagement(manager -> manager.sessionCreationPolicy(STATELESS))
            .authenticationProvider(authenticationProvider())
            .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        ;
        SecurityFilterChain chain = http.build();
        log.info("Configured security filter chain: {}",chain);
        return chain;
    }
Run Code Online (Sandbox Code Playgroud)

然后确保在类级别或单个方法级别的 REST 控制器上有 @CrossOrigin 注释。

@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
@CrossOrigin
public class AuthenticationController {
...
}
Run Code Online (Sandbox Code Playgroud)