Spring Boot受保护资源通过React(Axios)访问遇CORS错误,Postman正常
核心原因
Postman不会触发浏览器的CORS预检机制,但浏览器发送带Authorization这类自定义头的请求时,会先发送OPTIONS预检请求。当前配置存在两个关键问题:
- Spring Security过滤器优先级高于WebMvc的CORS配置,导致OPTIONS预检请求被Security认证逻辑拦截,无法返回正确的CORS响应头
- 客户端Axios配置中
Accept头设置错误(写为"/",正确应为"*/*"),可能触发预检请求的头校验失败
解决办法
方案一:在Spring Security中直接集成CORS配置(推荐)
放弃WebMvcConfigurer的CORS配置,改用Spring Security原生CORS配置,确保CORS过滤器在认证过滤器之前执行:
修改SecurityConfig类:
package com.telesco.demo.security; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import com.telesco.demo.services.MyUserDetailsService; import org.springframework.http.HttpMethod; @Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private MyUserDetailsService userDetailsService; @Autowired private JwtFilter jwtFilter; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { return http.csrf(customizer -> customizer.disable()) // 启用Spring Security原生CORS支持 .cors(Customizer.withDefaults()) .authorizeHttpRequests(request -> request .requestMatchers("api/register", "api/franchise/login", "publicquery", "api/isUserIdAvailable") .permitAll() // 允许所有OPTIONS预检请求直接通过 .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .anyRequest().authenticated()) .httpBasic(Customizer.withDefaults()) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class).build(); } @Bean public AuthenticationProvider authenticationProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setPasswordEncoder(new BCryptPasswordEncoder(12)); provider.setUserDetailsService(userDetailsService); return provider; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { return config.getAuthenticationManager(); } // 配置全局CORS规则 @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(java.util.List.of("http://localhost:5173")); configuration.setAllowedMethods(java.util.List.of("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD", "TRACE")); configuration.setAllowedHeaders(java.util.List.of("*")); // 允许携带Cookie等凭证(根据业务需求调整) configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
方案二:修复客户端Axios配置错误
修正Accept头的错误值,将"/"改为符合规范的"*/*":
api.interceptors.request.use( (config) => { const token = localStorage.getItem("token"); if (token) { config.headers.Authorization = `Bearer ${token}`; config.headers["Content-Type"] = "application/json"; // 修正Accept头为标准通配符格式 config.headers["Accept"] = "*/*"; config.headers["Accept-Encoding"] = "gzip, deflate, br"; config.headers["Connection"] = "keep-alive"; } return config; }, (error) => Promise.reject(error) );
验证步骤
- 重启Spring Boot服务
- 清除浏览器缓存后重新登录获取token
- 访问受保护资源
/api/items,此时浏览器OPTIONS预检请求会被正确处理,CORS错误消失
内容的提问来源于stack exchange,提问作者shank2111
相关产品推荐
相关产品推荐

