
本文详解如何在 spring boot 中正确配置跨域资源共享(cors),避免手动实现过滤器导致的预检失败、凭据冲突等问题,并提供基于 webmvcconfigurer 的标准、安全、可维护的配置方式。
本文详解如何在 spring boot 中正确配置跨域资源共享(cors),避免手动实现过滤器导致的预检失败、凭据冲突等问题,并提供基于 webmvcconfigurer 的标准、安全、可维护的配置方式。
在 Spring Boot 应用中,手动编写 CorsFilter 是常见但不推荐的做法——它极易引发 CORS 预检(preflight)失败,尤其在涉及认证头(如 Authorization)时。你遇到的错误:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
根本原因在于:手动过滤器未在预检请求(OPTIONS)响应中正确设置 CORS 头,且与 Spring Security 的拦截顺序冲突;更关键的是,Access-Control-Allow-Credentials: true 与 Access-Control-Allow-Origin: * 不可共存——这是 W3C 规范强制要求,而你的代码中同时设置了二者,直接导致浏览器拒绝响应。
✅ 正确做法:弃用自定义 CorsFilter,改用 Spring Boot 官方推荐的声明式 CORS 配置。
✅ 推荐方案:实现 WebMvcConfigurer
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/merchants/**") // 精确匹配路径(支持通配符)
.allowedOrigins("http://localhost:4200") // ❗禁止使用 "*" 当 allowCredentials = true
.allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD")
.allowedHeaders("Origin", "Accept", "X-Requested-With",
"Content-Type", "Authorization", "X-Auth-Token")
.exposedHeaders("Authorization", "X-Total-Count", "Link") // 前端 JS 可读取的响应头
.allowCredentials(true) // 允许携带 Cookie 或 Authorization 头
.maxAge(1800); // 预检缓存 30 分钟(秒)
}
}
⚠️ 注意事项:
- 若需支持凭据(如 JWT Token 或 Session Cookie),allowedOrigins *必须指定具体源(不能为 ``)**;
- 路径映射建议使用 /api/** 或 /merchants/** 等细粒度前缀,避免过度开放;
- allowedHeaders 中显式列出所需头(如 Authorization),而非依赖 *(部分旧版浏览器不支持);
- 若项目集成 Spring Security,请确保 CORS 配置优先于安全拦截——WebMvcConfigurer 自动适配,无需额外处理。
? 补充:Spring Security 中的 CORS 协同(如启用)
若使用 Spring Security(尤其 5.7+),还需显式启用其 CORS 支持:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(c -> c.configurationSource(corsConfigurationSource())) // 启用 CORS
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(authz -> authz
.requestMatchers("/public/**").permitAll()
.requestMatchers("/merchants/**").authenticated()
);
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"));
configuration.setAllowCredentials(true);
configuration.setExposedHeaders(Arrays.asList("Authorization", "X-Total-Count"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/merchants/**", configuration);
return source;
}
}
? 提示:若仅使用 WebMvcConfigurer 配置,且未显式禁用 Spring Security 的 CORS,则 Security 会自动桥接 MVC 的配置——但显式声明更清晰、可控。
✅ 总结
- ❌ 不要手写 CorsFilter:易出错、难调试、绕过 Spring 生命周期管理;
- ✅ 优先使用 WebMvcConfigurer#addCorsMappings():语义清晰、与 MVC 深度集成、自动处理预检;
- ✅ 凭据场景下,allowedOrigins 必须为白名单(非 *),否则浏览器静默拦截;
- ✅ 结合 Spring Security 时,通过 http.cors() 显式启用并复用配置,确保全链路一致。
遵循此方案,即可彻底解决带 Authorization 头的跨域请求被拦截问题,同时保障安全性与可维护性。











