https://docs.spring.io/spring-framework/reference/web/webmvc-cors.html
Spring MVC允许处理CORS(跨源资源共享)。
介绍
出于安全原因,浏览器禁止对当前源以外的资源进行AJAX调用。例如,可能在一个标签页中有银行账户,而在另一个标签页中有evil.com。evil.com上的脚本不应该能够使用你的凭据对你的银行API发起AJAX请求——例如从你的账户中提取资金!
跨源资源共享(CORS)是W3C规范,大多数浏览器都实现了这一规范。它允许你指定哪些跨域请求是授权的,而不是使用基于IFRAME或JSONP的较不安全且功能较弱的替代方案。
带凭据的请求
在使用CORS进行带凭据的请求时,需要启用allowedCredentials。此选项与配置的域建立高度信任,并且通过暴露敏感的用户特定信息(如cookie和CSRF令牌)增加了Web应用程序的攻击面。
启用凭据还会影响已配置的“*”CORS通配符的处理方式:
- 在allowOrigins中不允许使用通配符,但可以使用allowOriginPatterns属性来匹配一组动态来源。
- 当在allowedHeaders或allowedMethods中设置时,Access-Control-Allow-Headers和Access-Control-Allow-Methods响应头是通过复制CORS预探测请求(preflight request)中指定的相关头部和方法来处理的。
- 当在exposedHeaders中设置时,Access-Control-Expose-Headers响应头被设置为配置的头部列表或通配符字符。虽然CORS规范在Access-Control-Allow-Credentials设置为true时不允许使用通配符字符,但大多数浏览器都支持它,并且在CORS处理过程中并非所有响应头都是可用的。因此,无论allowCredentials属性的值如何,当指定时,通配符字符都将用作头部值。
虽然这种使用通配符的配置可能很方便,但建议在可能的情况下配置一个有限的值集,以提供更高级别的安全性。
处理
CORS规范区分了预探测请求(preflight request)、简单请求(simple request)和实际请求(actual request)。
Spring MVC 的 HandlerMapping 实现为 CORS 提供了内置支持。在成功将请求映射到处理器之后,HandlerMapping 实现会检查给定请求和处理器对应的 CORS 配置,并采取进一步的操作。预探测请求(Preflight requests)会被直接处理,而简单和实际的 CORS 请求则会被拦截、验证,并设置所需的 CORS 响应头。
为了启用跨域请求(即请求中存在 Origin 头部并且与请求的主机不同),你需要明确声明一些 CORS 配置。如果没有找到匹配的 CORS 配置,预探测请求将被拒绝。简单请求和实际 CORS 请求的响应中不会添加任何 CORS 头部,因此浏览器也会拒绝这些请求。
每个 HandlerMapping 可以根据 URL 模式配置单独的 CorsConfiguration 映射。在大多数情况下,应用程序使用 MVC Java 配置或 XML 命名空间来声明这些映射,结果是将一个全局映射传递给所有的 HandlerMapping 实例。
可以将 HandlerMapping 级别的全局 CORS 配置与更细粒度的处理器级别的 CORS 配置相结合。例如,使用注解的控制器可以在类或方法级别使用 @CrossOrigin 注解(其他处理器可以实现 CorsConfigurationSource)。
全局和局部配置相结合的规则通常是累加性的——例如,所有全局和所有局部来源。对于那些只能接受单个值的属性,例如 allowCredentials 和 maxAge,局部值将覆盖全局值。
@CrossOrigin
@CrossOrigin 注解允许在带注解的控制器方法上进行跨域请求,如下例所示:
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
默认情况下,@CrossOrigin 允许:
- 所有来源。
- 所有头部。
- 与控制器方法映射的所有 HTTP 方法。
allowCredentials 默认情况下并未启用,因为这建立了一种信任级别,会暴露敏感的用户特定信息(如 cookie 和 CSRF 令牌),因此只应在适当的情况下使用。当启用它时,要么必须将 allowOrigins 设置为一个或多个特定的域名(但不能是特殊值 “*”),或者可以使用 allowOriginPatterns 属性来匹配动态的一组来源。
maxAge 设置为 30 分钟。
@CrossOrigin 注解也支持在类级别上使用,并且会被所有方法继承,如下例所示:
@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
可以在类级别和方法级别上都使用 @CrossOrigin 注解,如下例所示:
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
全局配置
除了细粒度的控制器方法级别配置外,你可能还想定义一些全局 CORS 配置。可以在任何 HandlerMapping 上单独设置基于 URL 的 CorsConfiguration 映射。然而,大多数应用程序使用 MVC Java 配置或 MVC XML 命名空间来完成此操作。
默认情况下,全局配置启用以下内容:
- 所有来源。
- 所有头部。
- GET、HEAD 和 POST 方法。
allowCredentials 默认情况下并未启用,因为这建立了一种信任级别,会暴露敏感的用户特定信息(如 cookies 和 CSRF 令牌),因此只应在适当的情况下使用。当启用它时,必须将 allowOrigins 设置为一个或多个特定的域名(但不能是特殊值 “*”),或者可以使用 allowOriginPatterns 属性来匹配动态的一组来源。
maxAge 被设置为 30 分钟。
Java 配置
要在 MVC Java 配置中启用 CORS,可以使用 CorsRegistry 回调,如下例所示:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
// Add more mappings...
}
}
XML 配置
要在 XML 命名空间中启用 CORS,可以使用 <mvc:cors>
元素,如下例所示:
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="https://domain1.com, https://domain2.com"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2" allow-credentials="true"
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="https://domain1.com" />
</mvc:cors>
CORS 过滤器
可以通过内置的 CorsFilter 来应用 CORS 支持。
如果尝试将 CorsFilter 与 Spring Security 一起使用,请注意 Spring Security 内置了对 CORS 的支持。
要配置过滤器,请将 CorsConfigurationSource 传递给其构造函数,如下例所示:
CorsConfiguration config = new CorsConfiguration();
// Possibly...
// config.applyPermitDefaultValues()
config.setAllowCredentials(true);
config.addAllowedOrigin("https://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
CorsFilter filter = new CorsFilter(source);