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

Spring Boot 3中Spring Security的CORS预检请求401错误求助

解决Spring Boot 3 + Spring Security 预检OPTIONS请求401问题

核心原因

升级到Spring Boot 3后,JWT请求过滤器会拦截所有请求(包括OPTIONS预检请求),但OPTIONS请求不会携带Authorization令牌,导致被判定为未认证返回401;同时你的CORS配置存在冲突(通配符Origin与允许凭证不能共存),也会影响预检请求的正常处理。

解决方案步骤

1. 修改JWT过滤器,跳过OPTIONS请求

在你的JwtRequestFilter的doFilterInternal方法开头添加判断,直接放行OPTIONS请求:

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    // 直接放行OPTIONS预检请求
    if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
        response.setStatus(HttpServletResponse.SC_OK);
        filterChain.doFilter(request, response);
        return;
    }
    // 原有JWT令牌验证逻辑...
}

2. 调整SecurityFilterChain配置,明确放行OPTIONS请求

在authorizeHttpRequests中添加对OPTIONS请求的全局放行,确保Spring Security不会拦截它们:

@Bean
public SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity
            .cors(c -> c.configurationSource(corsConfigurationSource()))
            .csrf(c -> c.disable())
            .authorizeHttpRequests(requests -> requests
                    // 全局放行所有OPTIONS请求
                    .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                    .requestMatchers(
                        AntPathRequestMatcher.antMatcher("/comments/**"), 
                        AntPathRequestMatcher.antMatcher("/requests/admin/**")
                    ).authenticated()
                    .anyRequest().permitAll())
            .authenticationProvider(authenticationProvider())
            .exceptionHandling(r -> r.authenticationEntryPoint(jwtAuthenticationEntryPoint))
            .sessionManagement(r -> r.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    return httpSecurity.build();
}

3. 修复CORS配置的冲突问题

浏览器不允许**带凭证(AllowCredentials=true)**的CORS请求使用通配符*作为AllowedOrigins,必须指定具体的前端域名。修改你的CORS配置:

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration corsConfig = new CorsConfiguration();
    corsConfig.setAllowCredentials(true);
    // 替换为你的实际前端域名,多个可添加多个元素
    corsConfig.setAllowedOrigins(Arrays.asList("http://localhost:3000", "https://your-production-frontend.com"));
    // 明确允许的HTTP方法
    corsConfig.setAllowedMethods(Arrays.asList("GET", "PATCH", "POST", "OPTIONS", "PUT", "DELETE"));
    // 允许的请求头,包含Authorization(JWT令牌需要)
    corsConfig.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With"));
    // 暴露前端需要读取的响应头(比如返回的JWT令牌)
    corsConfig.setExposedHeaders(Arrays.asList("Authorization"));

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", corsConfig);
    return source;
}

验证

重启应用后,测试OPTIONS预检请求,应该返回200状态码,后续的实际请求也能正常通过认证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:52:34