SpringBoot配置CORS 跨源资源共享

27 阅读2分钟

跨源资源共享(Cross-Origin Resource Sharing,CORS)是一个由一系列传输的 HTTP 标头组成的系统。这些 HTTP 标头决定浏览器是否阻止前端 JavaScript 代码获取跨源请求的响应。

同源安全策略默认阻止“跨源”获取资源。但是 CORS 给了 Web 服务器这样的权限,即服务器可以选择允许跨源请求访问到它们的资源。

CORS是一种由 W3C 标准定义的跨域请求机制,允许浏览器通过设置 HTTP 请求头和响应头来实现跨域访问。CORS 是浏览器针对跨域请求的安全策略扩展,通过服务端显式声明哪些资源可以被特定来源访问,从而安全地实现跨域资源共享

SpringBoot 配置 CORS

通过 WebMvcConfigurer 全局配置

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class GlobalCorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 匹配所有路径
                .allowedOrigins("http://example.com", "http://another-domain.com")  // 允许的跨域域名
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")  // 允许的请求方法
                .allowedHeaders("*")  // 允许的请求头
                .allowCredentials(true)  // 是否允许发送 Cookie
                .maxAge(3600);  // 预检请求的缓存时间
    }
}

通过 @CrossOrigin注解局部配置

单个控制器方法

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/hello")
    @CrossOrigin(origins = "http://example.com", maxAge = 3600)
    public String hello() {
        return "world";
    }
}

全控制器

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://example.com", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST})
public class ApiController {

    @GetMapping("/hello")
    @CrossOrigin(origins = "http://example.com", maxAge = 3600)
    public String hello() {
        return "world";
    }
}

自定义过滤器

更高级的跨域控制,比如动态允许某些域名跨域,可以通过自定义 CorsFilter 来实现

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 强制类型转换为 HttpServletRequest 和 HttpServletResponse
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // 添加 CORS 响应头
        httpResponse.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有来源访问
        httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); // 允许的 HTTP 方法
        httpResponse.setHeader("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization"); // 允许的请求头
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); // 是否允许携带 Cookie

        // 处理 OPTIONS 请求(CORS 预检请求)
        if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
            httpResponse.setStatus(HttpServletResponse.SC_OK);
            return;
        }

        // 继续执行下一个过滤器链
        chain.doFilter(request, response);
    }
}

验证方法

打开浏览器的开发者工具,查看请求和响应头,确保响应中包含以下头信息:

  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods
  • Access-Control-Allow-Headers
  • Access-Control-Allow-Credentials

注意事项

  • Access-Control-Allow-Origin 设置
    • 如果需要限制特定的来源访问,可以将 "*" 替换为具体的域名,例如 "example.com"。
  • 安全性
    • 如果允许所有来源访问(*),可能存在安全风险,尤其是在涉及敏感数据的场景下。
  • OPTIONS 请求
    • 如果未正确处理 OPTIONS 请求,可能导致前端跨域失败。