此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
CORS
Spring MVC 允许你处理 CORS(跨域资源共享)。本节 介绍如何执行此作。
介绍
出于安全原因,浏览器禁止对当前源之外的资源进行 AJAX 调用。 例如,您可以将银行账户放在一个选项卡中,而 evil.com 放在另一个选项卡中。脚本 evil.com 中,应该无法使用 凭证 — 例如,从您的账户中取款!
凭证请求
将 CORS 与凭证请求一起使用需要启用allowedCredentials
.请注意,
此选项与配置的域建立高级别的信任,并且还会增加
通过公开敏感的用户特定信息,Web 应用程序的攻击面
例如 Cookie 和 CSRF 令牌。
启用凭证还会影响已配置 CORS 通配符的处理方式:"*"
-
通配符在 中未获得授权
allowOrigins
,但也可以 这allowOriginPatterns
属性可用于匹配一组动态的源。 -
当设置为
allowedHeaders
或allowedMethods
这Access-Control-Allow-Headers
和Access-Control-Allow-Methods
响应标头的处理方法是将相关的 标头和方法。 -
当设置为
exposedHeaders
,Access-Control-Expose-Headers
响应标头 添加到配置的标头列表或通配符。虽然 CORS 规范 不允许使用通配符Access-Control-Allow-Credentials
设置为true
,则大多数浏览器都支持它,并且响应标头在 CORS 处理,因此通配符是 指定,而不管allowCredentials
财产。
虽然这种通配符配置可能很方便,但建议在可能的情况下配置 一组有限的值,以提供更高级的安全性。 |
加工
CORS 规范区分了印前检查请求、简单请求和实际请求。 要了解 CORS 的工作原理,您可以阅读这篇文章,其中 许多其他方法,或者参见 规范 了解更多详情。
Spring MVCHandlerMapping
implementations 提供对 CORS 的内置支持。成功后
将请求映射到处理程序,HandlerMapping
implementations 检查 CORS 配置的
given request 和 handler 并采取进一步的作。处理印前检查请求
直接,而简单和实际的 CORS 请求被拦截、验证,并且具有
所需的 CORS 响应标头集。
为了启用跨域请求(即Origin
header 存在且
与请求的主机不同),您需要有一些显式声明的 CORS
配置。如果未找到匹配的 CORS 配置,则印前 Backup 请求为
拒绝。没有 CORS 标头添加到简单和实际 CORS 请求的响应中
因此,浏览器会拒绝它们。
每HandlerMapping
可以使用基于 URL 模式的 URL 进行单独配置CorsConfiguration
映射。在大多数情况下,应用程序
使用 MVC Java 配置或 XML 命名空间来声明此类映射,这将产生
在传递给所有HandlerMapping
实例。
您可以在HandlerMapping
Level with More (更多级别)
精细的处理程序级 CORS 配置。例如,带注解的控制器可以使用
类级或方法级@CrossOrigin
注解(其他处理程序可以实现CorsConfigurationSource
).
组合全局配置和本地配置的规则通常是累加的 — 例如,
所有全球和所有本地源。对于只能使用单个值
accepted,例如allowCredentials
和maxAge
,则 local 将覆盖 global 值。看CorsConfiguration#combine(CorsConfiguration)
了解更多详情。
要从源代码中了解更多信息或进行高级自定义,请检查背后的代码:
|
@CrossOrigin
这@CrossOrigin
annotation 支持对带注解的控制器方法进行跨域请求,
如下例所示:
-
Java
-
Kotlin
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin
@GetMapping("/{id}")
fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
fun remove(@PathVariable id: Long) {
// ...
}
}
默认情况下,@CrossOrigin
允许:
-
所有来源。
-
所有标头。
-
控制器方法映射到的所有 HTTP 方法。
allowCredentials
默认情况下不启用,因为这会建立信任级别
公开敏感的用户特定信息(例如 cookie 和 CSRF 令牌)和
应仅在适当的情况下使用。启用时allowOrigins
必须是
设置为一个或多个特定域(但不是 Special Value )或
这"*"
allowOriginPatterns
属性可用于匹配一组动态的源。
maxAge
设置为 30 分钟。
@CrossOrigin
在类级别也受支持,并且被所有方法继承。
如下例所示:
-
Java
-
Kotlin
@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(origins = ["https://domain2.com"], maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
@GetMapping("/{id}")
fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
fun remove(@PathVariable id: Long) {
// ...
}
您可以使用@CrossOrigin
在类级别和方法级别,
如下例所示:
-
Java
-
Kotlin
@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) {
// ...
}
}
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {
@CrossOrigin("https://domain2.com")
@GetMapping("/{id}")
fun retrieve(@PathVariable id: Long): Account {
// ...
}
@DeleteMapping("/{id}")
fun remove(@PathVariable id: Long) {
// ...
}
}
全局配置
除了细粒度的 controller 方法级配置之外,您可能还希望
也定义一些全局 CORS 配置。您可以设置基于 URLCorsConfiguration
映射HandlerMapping
.但是,大多数应用程序都使用
MVC Java 配置或 MVC XML 命名空间来执行此作。
默认情况下,全局配置将启用以下功能:
-
所有来源。
-
所有标头。
-
GET
,HEAD
和POST
方法。
allowCredentials
默认情况下不启用,因为这会建立信任级别
公开敏感的用户特定信息(例如 cookie 和 CSRF 令牌)和
应仅在适当的情况下使用。启用时allowOrigins
必须是
设置为一个或多个特定域(但不是 Special Value )或
这"*"
allowOriginPatterns
属性可用于匹配一组动态的源。
maxAge
设置为 30 分钟。
Java 配置
要在 MVC Java 配置中启用 CORS,您可以使用CorsRegistry
回调
如下例所示:
-
Java
-
Kotlin
@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...
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
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
.
如果您尝试使用CorsFilter 使用 Spring Security,请记住 Spring
安全性内置了对
CORS 的。 |
要配置过滤器,请传递CorsConfigurationSource
添加到其构造函数中,作为
以下示例显示:
-
Java
-
Kotlin
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);
val config = CorsConfiguration()
// Possibly...
// config.applyPermitDefaultValues()
config.allowCredentials = true
config.addAllowedOrigin("https://domain1.com")
config.addAllowedHeader("*")
config.addAllowedMethod("*")
val source = UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", config)
val filter = CorsFilter(source)