You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3.0 CORS配置失效问题排查与解决咨询

Spring Boot 3.0 + Spring Security CORS配置不生效问题解决

问题现象

在Spring Boot 3.0项目中配置CORS策略后未生效:

  • 初始配置下,请求响应头缺失Access-Control-Allow-Origin字段,响应头信息如下:
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Mon, 13 Feb 2023 10:33:36 GMT
  • 尝试通过http.cors().configurationSource(corsConfigurationSource())启用CORS后,出现403错误响应:
* Mark bundle as not supporting multiuse
< HTTP/1.1 403
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Transfer-Encoding: chunked
< Date: Mon, 13 Feb 2023 12:46:25 GMT
  • 即使请求成功,响应头仍未返回期望的Access-Control-Allow-Origin: *:
Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Allow: GET,HEAD,OPTIONS
< Accept-Patch:
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 0
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Length: 0
< Date: Mon, 13 Feb 2023 13:28:44 GMT

原因分析

  1. 初始配置直接禁用CORS:原代码中http.csrf().disable().cors().disable()完全关闭了Spring Security的CORS处理逻辑,导致自定义CORS配置无法生效。
  2. CORS配置未包含预检请求方法:自定义CORS仅允许GET方法,未覆盖浏览器预检请求必需的OPTIONS方法,导致预检请求被拦截触发403。
  3. 过滤器顺序问题:CORS配置的执行顺序晚于权限校验,导致OPTIONS请求未被正确放行。

解决方案

步骤1:修改SecurityFilterChain配置,启用自定义CORS源

删除.cors().disable(),将CORS配置放在权限校验之前,确保过滤器优先级正确:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, Jwt2AuthenticationConverter authenticationConverter, ServerProperties serverProperties) throws Exception {
    // 优先配置CORS,关联自定义配置源
    http.cors().configurationSource(corsConfigurationSource());
    
    http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(authenticationConverter);
    http.anonymous();
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    http.csrf().disable(); // 仅保留CSRF禁用

    http.exceptionHandling().authenticationEntryPoint((request, response, authException) -> {
        response.addHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Restricted Content\"");
        response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
    });

    if (serverProperties.getSsl() != null && serverProperties.getSsl().isEnabled()) {
        http.requiresChannel().anyRequest().requiresSecure();
    } else {
        http.requiresChannel().anyRequest().requiresInsecure();
    }

    http.authorizeRequests()
            .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .requestMatchers("/swagger-ui/**", "/api-docs/**").permitAll()
            .requestMatchers(HttpMethod.GET, "/attributes/questions", "/attr-values/recent-values", "/attr-values/history")
                .hasAuthority("default-roles-ai-solutions")
            .requestMatchers(HttpMethod.POST, "/attr-values/save-attr-values")
                .hasAuthority("default-roles-ai-solutions")
            .anyRequest().authenticated()
            .and().oauth2ResourceServer().jwt();
    return http.build();
}

步骤2:更新CORS配置,添加OPTIONS方法

修改CORS配置,确保允许的方法包含预检请求必需的OPTIONS:

@Bean
CorsConfigurationSource corsConfigurationSource() {
    final var configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    // 添加OPTIONS方法,支持浏览器预检请求
    configuration.setAllowedMethods(Arrays.asList("GET", "OPTIONS"));
    configuration.setAllowedHeaders(Arrays.asList("*"));
    configuration.setExposedHeaders(Arrays.asList("*"));
    // 如需允许带凭证的请求,可开启此配置(不需要则删除)
    configuration.setAllowCredentials(true);

    final var source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);

    return source;
}

步骤3:验证生效

重启项目后发送请求,响应头将包含Access-Control-Allow-Origin: *,OPTIONS预检请求也会返回正常的200状态。

内容的提问来源于stack exchange,提问作者nicepeopleproject

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 14:41:44