对于最新稳定版本,请使用Spring Framework 7.0.1spring-doc.cadn.net.cn

CORS

Spring MVC 允许你处理 CORS(跨原点资源共享)。本节描述了如何实现这一点。spring-doc.cadn.net.cn

介绍

出于安全考虑,浏览器禁止AJAX调用当前来源以外的资源。例如,你可以把银行账户放在一个标签页,evil.com 在另一个标签页。 脚本 evil.com 不应该能用你的凭证向你的银行 API 发送 AJAX 请求——比如从你的账户中取款!spring-doc.cadn.net.cn

跨源资源共享(CORS)是大多数浏览器实现的W3C规范,允许你指定授权哪些类型的跨域请求,而不是使用安全性较低且功能较弱的基于IFRAME或JSONP的变通方法。spring-doc.cadn.net.cn

凭证请求

使用带有凭证请求的 CORS 需要启用允许的资格. 请注意该选项建立了与配置域的高度信任,同时也增加了通过暴露敏感用户特定信息,提高网络应用的攻击表层如 cookie 和 CSRF Tokens。spring-doc.cadn.net.cn

启用凭证还会影响配置后的CORS万用符处理方式:"*"spring-doc.cadn.net.cn

  • 万能牌不被授权allowOrigins,但另一种方式 这allowOriginPatterns属性可用于匹配动态的原点集合。spring-doc.cadn.net.cn

  • 启动时允许的头部允许方法访问控制允许头访问-控制-允许-方法响应头通过复制相关的CORS预检请求中指定的头部和方法来处理。spring-doc.cadn.net.cn

  • 启动时exposedHeaders,访问控制-暴露-头部响应头被设置为要么设置为配置的头列表,要么设置为万用字符。虽然 CORS 规范不允许在访问-控制-允许-凭证设置为true,大多数浏览器支持,且响应头部在CORS 处理过程中并非全部可用,因此通配符字符即为当指定的头值,无论allowCredentials财产。spring-doc.cadn.net.cn

虽然这种通配卡配置很方便,但建议尽可能配置 而是用有限的数值来提供更高的安全性。

加工

CORS规范区分了印前请求、简单请求和实际请求。 想了解CORS的工作原理,你可以阅读这篇文章 还有许多其他,或查看规范以获取更多细节。spring-doc.cadn.net.cn

春季MVC处理器映射实现为 CORS 提供了内置支持。成功之后 将请求映射到处理器,处理器映射实现检查 CORS 配置以 收到请求并处理后采取进一步行动。会处理检查前请求 直接,简单且实际的CORS请求会被拦截、验证,并且 必须设置 CORS 响应头。spring-doc.cadn.net.cn

为了启用跨源请求(即起源首部存在,且 与请求的主机不同),你需要有明确声明的 CORS 配置。如果找不到匹配的CORS配置,则会进行检查前检查请求 拒绝。简单和实际的 CORS 请求响应中不会添加 CORS 头部 因此,浏览器会拒绝它们。spring-doc.cadn.net.cn

处理器映射可以通过基于URL模式的单独配置CorsConfiguration映射。在大多数情况下,应用 使用 MVC Java 配置或 XML 命名空间来声明此类映射,结果 在一个全局映射中传递给所有处理器映射实例。spring-doc.cadn.net.cn

你可以在处理器映射与更多人同级 细粒度、处理级别的 CORS 配置。例如,带注释的控制器可以使用 类级或方法级@CrossOrigin注释(其他处理程序可以实现)CorsConfigurationSource).spring-doc.cadn.net.cn

组合全局配置和局部配置的规则通常是加法的——例如, 全是全球起源,全是本地起源。对于那些只能有一个值的属性 接受,例如:allowCredentials最大年龄,局部值覆盖全局值。看CorsConfiguration#combine(CorsConfiguration)更多细节请阅读。spring-doc.cadn.net.cn

想了解更多源代码或进行高级定制,请查看背后的代码:spring-doc.cadn.net.cn

@CrossOrigin

@CrossOrigin注释使得对带注释的控制器方法实现交叉起点请求, 如下示例所示:spring-doc.cadn.net.cn

@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允许:spring-doc.cadn.net.cn

allowCredentials默认情况下不启用,因为这会建立信任级别 它暴露了敏感的用户特定信息(如Cookie和CSRFTokens),并且 应仅在适当情况下使用。启用时allowOrigins一定是 设置为一个或多个特定域(但不包括特殊值),或者 这"*"allowOriginPatterns属性可用于匹配动态的原点集合。spring-doc.cadn.net.cn

最大年龄设置为30分钟。spring-doc.cadn.net.cn

@CrossOrigin也支持类级,并且所有方法都继承, 如下示例所示:spring-doc.cadn.net.cn

@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无论是在班级还是方法层面, 如下示例所示:spring-doc.cadn.net.cn

@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) {
		// ...
	}
}

全局配置

除了细粒度的控制器方法层级配置外,你可能还想 还定义一些全局CORS配置。你可以设置基于网址的CorsConfiguration任意处理器映射.然而,大多数应用使用以下 MVC Java 配置或 MVC XML 命名空间来实现这一点。spring-doc.cadn.net.cn

默认情况下,全局配置支持以下功能:spring-doc.cadn.net.cn

allowCredentials默认情况下不启用,因为这会建立信任级别 它暴露了敏感的用户特定信息(如Cookie和CSRFTokens),并且 应仅在适当情况下使用。启用时allowOrigins一定是 设置为一个或多个特定域(但不包括特殊值),或者 这"*"allowOriginPatterns属性可用于匹配动态的原点集合。spring-doc.cadn.net.cn

最大年龄设置为30分钟。spring-doc.cadn.net.cn

Java 配置

要在MVC Java配置中启用CORS,你可以使用CorsRegistry回调 如下示例所示:spring-doc.cadn.net.cn

@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>元素 如下示例所示:spring-doc.cadn.net.cn

<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>

CORSFilter

你可以通过内置功能应用CORS支持。CorsFilter.spring-doc.cadn.net.cn

如果你尝试使用CorsFilter与春季安全一起,请记住Spring 安全性内置支持 科尔斯。

要配置过滤器,通过CorsConfigurationSource与其构造器相符,作为 以下示例展示了:spring-doc.cadn.net.cn

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)