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
相关产品推荐
相关产品推荐

