首页 > Java > 跨域 springboot解决方案

跨域 springboot解决方案

2025-04-02 11:26:09

跨域发生和场景,看这里


一、Spring Boot 跨域解决方案总览

方案 适用场景 特点
@CrossOrigin 注解 单个控制器/方法 简单快捷,局部控制
全局 CORS 配置 全项目统一规则 集中管理,优先级高
Spring Security 集成 安全框架整合场景 与权限控制结合
自定义过滤器 特殊需求(如动态域名) 高度灵活,手动控制

二、具体实现方案

方案1:@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");
    }
}

特点

  • 粒度控制,适合不同接口差异化配置
  • 需在每个控制器/方法重复添加注解

方案2:全局 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 注解
  • 生产环境务必指定具体域名(避免 *

方案3:Spring Security 集成方案

@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;
    }
}

特点

  • 与安全策略深度整合
  • 适合需要权限控制的接口
  • 配置优先级高于全局 CORS 配置

方案4:自定义过滤器(动态域名等特殊场景)

@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; // 示例代码,需替换为实际校验
    }
}

特点

  • 完全手动控制响应头
  • 适合需要动态域名授权的场景
  • 可能与其他 CORS 配置冲突(需注意优先级)

三、关键配置说明

1. 允许凭证(Cookies/认证)

  • 必须同时满足:
    • allowCredentials(true)
    • allowedOrigins 不能使用 *,必须指定具体域名
    • 前端请求需设置 withCredentials: true(浏览器端)

2. 预检请求(OPTIONS)处理

  • Spring Boot 自动处理 OPTIONS 请求,无需手动实现
  • 通过 maxAge 设置预检缓存时间(减少请求次数)

3. 安全建议

  • 生产环境禁用 allowedOrigins("*")
  • 敏感接口限制 HTTP 方法(如只允许 GET/POST)
  • 使用 exposedHeaders 替代 allowedHeaders("*") 最小化暴露头信息

四、常见问题排查

问题1:CORS 配置不生效

  • 可能原因
    • 多个 CORS 配置冲突(如同时使用全局配置和 Security 配置)
    • 过滤器顺序问题(自定义过滤器需设置 @Order(Ordered.HIGHEST_PRECEDENCE)
    • 路径匹配错误(检查 addMapping("/**") 是否覆盖目标接口)
  • 检查项
    • 服务端是否设置 allowCredentials(true)
    • 前端请求是否添加 credentials: 'include'(浏览器端)
    • Cookie 的 SameSite 属性是否设置为 None
    • 是否使用 HTTPS(Secure 属性要求)

问题3:自定义头被拦截

  • 解决方案
    • 在 allowedHeaders 中添加自定义头名称
    • 若需要前端访问响应头,需在 exposedHeaders 中声明

五、最佳实践组合

  1. 开发环境

    // 全局配置(临时允许所有源)
    .allowedOrigins("*")
    .allowedMethods("*")
    
  2. 生产环境

    // Spring Security 配置(安全严格)
    config.setAllowedOrigins(List.of("https://production-domain.com"));
    config.setAllowedMethods(List.of("GET", "POST"));
    config.setExposedHeaders(List.of("X-Info"));
    
使用 Ctrl+D 可将网站添加到书签
收藏网站
扫描二维码
关注早实习微信公众号
官方公众号
Top