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

SpringBoot 3.1.2升级后,Angular+Nginx代理的CORS配置异常求助

SpringBoot 3.1.2升级后CORS 403问题解决指南

问题背景

将SpringBoot版本从2.x升级至3.1.2后,前端从https://www.example.com发起的请求到data.example.com时,返回403并提示“Invalid CORS request”。架构为:www.example.com通过CloudFront分发,data.example.com指向EC2实例,Nginx代理请求到SpringBoot应用,已排除身份认证问题,确认是CORS配置拦截。

核心原因

  1. Spring Security 6.x校验升级:SpringBoot3对应Spring Security6,CORS校验逻辑更严格,必须明确配置AllowedOrigins,否则即使Nginx设置了CORS头,Spring Security仍会拦截请求。
  2. Nginx配置冗余冲突:同时在Nginx的server块和proxy请求中设置CORS头,导致请求头被重复传递给后端,干扰Spring的CORS校验。

解决步骤

1. 调整Spring Security CORS配置

生产环境必须明确配置允许的Origin,不能依赖Nginx,同时规范允许的请求头:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity( 
        securedEnabled = true,
        jsr250Enabled = true
)
public class SecurityConfig {
    private final Environment environment;

    // 构造注入Environment
    public SecurityConfig(Environment environment) {
        this.environment = environment;
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        // 允许的请求方法
        configuration.setAllowedMethods(List.of("POST","PUT","GET", "PATCH", "OPTIONS"));
        // 允许携带凭证
        configuration.setAllowCredentials(true);
        // 区分环境配置允许的Origin
        if (Arrays.stream(environment.getActiveProfiles()).anyMatch("development"::equalsIgnoreCase)) {
            configuration.setAllowedOrigins(List.of("http://localhost:4200"));
        } else {
            // 生产环境建议从配置文件读取,比如@Value("${cors.allowed-origins}")
            configuration.setAllowedOrigins(List.of("https://www.example.com"));
        }
        // 明确允许的请求头,避免Spring拦截自定义头
        configuration.setAllowedHeaders(List.of(
                "Authorization", "Accept", "Origin", "DNT", "X-CustomHeader",
                "Keep-Alive", "User-Agent", "X-Requested-With", "If-Modified-Since",
                "Cache-Control", "Content-Type", "Content-Range", "Range"
        ));
        
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
                .cors(withDefaults()) 
                // 保留原有角色/URL匹配配置...
                .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }
}

2. 优化Nginx代理配置

移除冗余的CORS头设置,仅处理OPTIONS预检请求:

server {
   listen 443 ssl;
   server_name data.example.com;

   ssl_certificate              /etc/ssl/certs/data.example.com.crt;
   ssl_certificate_key          /etc/ssl/certs/data.example.com.key;
   ssl_protocols                TLSv1.2 TLSv1.3; # 建议启用更安全的TLS版本

   error_log /var/log/nginx/error.log;
   access_log /var/log/nginx/access.log;

  location / {
        # 仅处理OPTIONS预检请求,返回必要的CORS响应头
        if ($request_method = 'OPTIONS') {
            add_header Access-Control-Allow-Origin https://www.example.com always;
            add_header Access-Control-Allow-Credentials true always;
            add_header Access-Control-Allow-Headers Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range always;
            add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT,DELETE,PATCH always;
            add_header Access-Control-Max-Age 1728000 always;
            add_header Content-Type 'text/plain charset=UTF-8' always;
            add_header Content-Length 0 always;
            return 204;
        }

        proxy_http_version  1.1;

        # 移除所有CORS相关的proxy_set_header,避免传递给后端干扰校验
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        proxy_pass http://127.0.0.1:8080;
  }

  location ~ /.well-known {
        allow all;
  }
}

server {
    listen      80;
    return      301 https://$host$request_uri; # 建议HTTP重定向到HTTPS,提升安全性
}

验证要点

  1. 重启SpringBoot应用和Nginx服务
  2. 用浏览器开发者工具检查请求头:
    • 预检OPTIONS请求返回204
    • 实际请求的响应头包含Access-Control-Allow-Origin: https://www.example.com,且无重复头
  3. 确认请求不再返回403错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:10:57