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

ReactJS前端向Spring Boot后端发送Bearer Token时遇CORS错误

解决React前端向Spring Boot后端发送JWT令牌时的CORS错误

问题根源分析

Postman能正常请求但前端报错,核心原因是浏览器的预检OPTIONS请求被Spring Security拦截,或者自定义CORS过滤器的执行顺序不对,导致CORS响应头未正确返回。

解决方案

方案1:在Spring Security中直接配置CORS(推荐,替代自定义CorsFilter)

删除自定义的CorsFilter类,直接在SecurityFilterChain中集成CORS配置,确保CORS处理在Security认证之前执行:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http
            .csrf(customizer -> customizer.disable())
            // 新增CORS配置
            .cors(cors -> cors.configurationSource(corsConfigurationSource()))
            .authorizeHttpRequests(request -> request
                    // 放行OPTIONS预检请求
                    .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                    // 公开端点(无需认证)
                    .requestMatchers("/auth/register", "/auth/login", "/auth/google", "/products/**").permitAll()
                    // 用户专属端点(需认证)
                    .requestMatchers("/orders/**", "/shipping/**","/cart/**").hasRole("USER")
                    // 管理员专属端点(需认证+角色)
                    .requestMatchers("/admin/**").hasRole("ADMIN")
                    // 其他所有请求需认证
                    .anyRequest().authenticated())
            .httpBasic(Customizer.withDefaults())
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .exceptionHandling(exception -> exception.authenticationEntryPoint(new CustomAuthenticationEntryPoint()))
            .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
            .build();
}

// 定义CORS配置源
@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.setAllowedOrigins(Arrays.asList("http://localhost:5173"));
    config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept", "Authorization"));
    config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
    config.addExposedHeader("Authorization");
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    return source;
}

方案2:修复自定义CorsFilter的执行顺序

如果坚持使用自定义CorsFilter,需确保它在Spring Security过滤器之前执行,添加@Order(Ordered.HIGHEST_PRECEDENCE)注解:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 确保此过滤器最先执行
public class CorsFilter extends OncePerRequestFilter {
    // 原有的doFilterInternal代码保持不变
}

同时在SecurityFilterChain中放行OPTIONS请求:

.authorizeHttpRequests(request -> request
        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
        // 其他原有配置...
)

前端请求验证

确保React请求中开启withCredentials,以axios为例:

// 单个请求配置
axios.get('/api/orders', {
    headers: {
        'Authorization': 'Bearer ' + token
    },
    withCredentials: true
});

// 全局配置
axios.defaults.withCredentials = true;

关键注意点

  • 必须放行OPTIONS请求:浏览器发送带自定义头(如Authorization)的请求前,会先发送OPTIONS预检请求,该请求无需认证,必须允许通过。
  • CORS配置要一致:后端allowedOrigins必须和前端地址完全匹配(含端口),当allowCredentials为true时,不能使用通配符*。
  • 过滤器顺序:CORS处理必须在任何认证过滤器之前执行,否则预检请求会被拦截。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:55:17