跨域发生和场景,看这里
| 方案 | 适用场景 | 特点 | 
|---|---|---|
| @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 属性是否设置为 NoneSecure 属性要求)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"));