跨域发生和场景,看这里
方案 | 适用场景 | 特点 |
---|---|---|
@CrossOrigin 注解 |
单个控制器/方法 | 简单快捷,局部控制 |
全局 CORS 配置 | 全项目统一规则 | 集中管理,优先级高 |
Spring Security 集成 | 安全框架整合场景 | 与权限控制结合 |
自定义过滤器 | 特殊需求(如动态域名) | 高度灵活,手动控制 |
@CrossOrigin
注解(局部控制)@RestController
public class ApiController {
// 允许所有源访问(开发环境便捷方案)
@CrossOrigin(origins = "*")
@GetMapping("/api/public-data")
public String publicData() {
return "Public data (CORS enabled)";
}
// 指定允许的源(生产推荐)
@CrossOrigin(
origins = "https://trusted-domain.com",
allowedHeaders = "*",
methods = {RequestMethod.GET, RequestMethod.POST},
allowCredentials = "true" // 允许凭证(如Cookie)
)
@PostMapping("/api/secure-data")
public ResponseEntity<?> secureData() {
return ResponseEntity.ok("Secure data with CORS");
}
}
特点:
@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 匹配所有路径
.allowedOrigins("https://trusted-domain.com", "https://your-miniapp.com") // 允许的源
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的方法
.allowedHeaders("*") // 允许的请求头
.exposedHeaders("X-Custom-Header") // 暴露的响应头
.allowCredentials(true) // 允许凭证(需明确 origins)
.maxAge(3600); // 预检请求缓存时间(秒)
}
};
}
}
特点:
@CrossOrigin
注解*
)@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().configurationSource(corsConfigurationSource()) // 启用CORS
.and()
.csrf().disable() // 根据需求决定是否关闭CSRF
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.anyRequest().authenticated();
}
// CORS 配置(优先级最高)
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("https://trusted-domain.com"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowCredentials(true); // 允许凭证
config.setExposedHeaders(Arrays.asList("X-Auth-Token")); // 暴露自定义头
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config); // 全局生效
return source;
}
}
特点:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 确保过滤器优先级最高
public class CustomCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
// 动态设置允许的源(例如从数据库读取)
String origin = request.getHeader("Origin");
if (isAllowedOrigin(origin)) { // 自定义校验逻辑
response.setHeader("Access-Control-Allow-Origin", origin);
}
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(req, res);
}
private boolean isAllowedOrigin(String origin) {
// 实现动态域名校验逻辑(例如白名单检查)
return true; // 示例代码,需替换为实际校验
}
}
特点:
allowCredentials(true)
allowedOrigins
不能使用 *
,必须指定具体域名withCredentials: true
(浏览器端)maxAge
设置预检缓存时间(减少请求次数)allowedOrigins("*")
exposedHeaders
替代 allowedHeaders("*")
最小化暴露头信息@Order(Ordered.HIGHEST_PRECEDENCE)
)addMapping("/**")
是否覆盖目标接口)allowCredentials(true)
credentials: 'include'
(浏览器端)SameSite
属性是否设置为 None
Secure
属性要求)allowedHeaders
中添加自定义头名称exposedHeaders
中声明开发环境:
// 全局配置(临时允许所有源)
.allowedOrigins("*")
.allowedMethods("*")
生产环境:
// Spring Security 配置(安全严格)
config.setAllowedOrigins(List.of("https://production-domain.com"));
config.setAllowedMethods(List.of("GET", "POST"));
config.setExposedHeaders(List.of("X-Info"));