Spring Boot配置Spring Security CORS仍报错,求排查方案
排查Spring Boot + React CORS问题:Postman正常但前端报错的解决思路
嘿,我之前踩过一模一样的坑!Postman能正常请求但React一调用就报CORS错,核心原因其实是浏览器的预检请求(OPTIONS)没被正确处理——Postman不会自动发OPTIONS预检,但React在发送带自定义头(比如你的JWT Token)或者非简单请求时,浏览器会先发起OPTIONS请求确认权限,这时候你的Security配置可能把这个预检请求拦截了。
咱们一步步来修正:
1. 先给OPTIONS请求开绿灯
你的Security配置里只放行了POST /login,但OPTIONS请求是浏览器自动发起的,还没带JWT Token,肯定会被拦截。在authorizeRequests里加一行,放行所有OPTIONS请求:
@Override protected void configure(HttpSecurity http) throws Exception { http .cors().and().csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .addFilter(new JwtAuthorizationFilter(authenticationManager(), this.userRepository)) .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 新增这行,放行所有OPTIONS请求 .antMatchers(HttpMethod.POST, "/login").permitAll() .antMatchers("/iotd").hasRole("USER") .anyRequest().authenticated(); }
2. 把CORS配置整合到Spring Security中,避免优先级冲突
你之前分开用WebMvcConfigurer配CORS,可能会被Spring Security的CORS配置覆盖。直接在Security里指定CORS配置更可靠:
第一步:移除原来的CorsConfig类(或者注释掉)
第二步:在Security配置里添加CORS配置源
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { // 注入你的userRepository... @Override protected void configure(HttpSecurity http) throws Exception { http // 替换原来的cors().and(),用自定义的配置源 .cors(cors -> cors.configurationSource(corsConfigurationSource())).and().csrf().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilter(new JwtAuthenticationFilter(authenticationManager())) .addFilter(new JwtAuthorizationFilter(authenticationManager(), this.userRepository)) .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers(HttpMethod.POST, "/login").permitAll() .antMatchers("/iotd").hasRole("USER") .anyRequest().authenticated(); } // 新增CORS配置源Bean @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("*")); // 生产环境一定要改成你的前端域名,比如"http://localhost:3000" config.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS")); config.setAllowedHeaders(Arrays.asList("*")); config.setAllowCredentials(true); // 如果前端要带Cookie/认证信息,必须设为true,同时origin不能是* UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } }
3. 确保JWT过滤器跳过OPTIONS请求
你的JwtAuthenticationFilter和JwtAuthorizationFilter可能会拦截OPTIONS请求,导致预检失败。在过滤器的doFilterInternal方法开头加判断,直接放行OPTIONS请求:
以JwtAuthenticationFilter为例:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // 新增:如果是OPTIONS请求,直接返回200 if (HttpMethod.OPTIONS.name().equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); return; } // 原来的JWT验证逻辑... chain.doFilter(request, response); }
JwtAuthorizationFilter也要做同样的修改!
最后验证
重启Spring Boot应用,再用React调用试试——应该就能正常跨域了。另外提醒下,生产环境千万不要用allowedOrigins("*"),要指定具体的前端域名,避免安全风险。
内容的提问来源于stack exchange,提问作者Bjorn Kristensson
相关产品推荐
相关产品推荐

