此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.0spring-doc.cn

CORS

Spring MVC 允许你处理 CORS(跨域资源共享)。本节 介绍如何执行此操作。spring-doc.cn

介绍

出于安全原因,浏览器禁止对当前源之外的资源进行 AJAX 调用。 例如,您可以将银行账户放在一个选项卡中,而 evil.com 放在另一个选项卡中。脚本 evil.com 中,应该无法使用 凭证 — 例如,从您的账户中取款!spring-doc.cn

跨域资源共享 (CORS) 是大多数浏览器实现的 W3C 规范,允许您指定 授权什么样的跨域请求,而不是使用安全性较低且较少 基于 IFRAME 或 JSONP 的强大解决方法。spring-doc.cn

凭证请求

将 CORS 与凭证请求一起使用需要启用 。请注意, 此选项与配置的域建立高级别的信任,并且还会增加 通过公开敏感的用户特定信息,Web 应用程序的攻击面 例如 Cookie 和 CSRF 令牌。allowedCredentialsspring-doc.cn

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

  • 通配符在 中未获得授权,但可以选择 该属性可用于匹配一组动态的 Origins。allowOriginsallowOriginPatternsspring-doc.cn

  • 当设置为 or 时,和响应标头通过复制相关的 标头和方法。allowedHeadersallowedMethodsAccess-Control-Allow-HeadersAccess-Control-Allow-Methodsspring-doc.cn

  • 设置为 on 时,将设置响应标头 添加到配置的标头列表或通配符。虽然 CORS 规范 不允许使用通配符 when 设置为 ,大多数浏览器都支持通配符,并且响应标头在 CORS 处理,因此通配符是 无论属性的值如何,都指定。exposedHeadersAccess-Control-Expose-HeadersAccess-Control-Allow-CredentialstrueallowCredentialsspring-doc.cn

虽然这种通配符配置可能很方便,但建议在可能的情况下配置 一组有限的值,以提供更高级的安全性。

加工

CORS 规范区分了印前检查请求、简单请求和实际请求。 要了解 CORS 的工作原理,您可以阅读这篇文章,其中 许多其他方法,或者参见 规范 了解更多详情。spring-doc.cn

Spring MVC 实现提供了对 CORS 的内置支持。成功后 将请求映射到处理程序,实现会检查 CORS 配置的 given request 和 handler 并采取进一步的操作。处理印前检查请求 直接,而简单和实际的 CORS 请求被拦截、验证,并且具有 所需的 CORS 响应标头集。HandlerMappingHandlerMappingspring-doc.cn

为了启用跨域请求(即,标头存在且 与请求的主机不同),您需要有一些显式声明的 CORS 配置。如果未找到匹配的 CORS 配置,则印前 Backup 请求为 拒绝。没有 CORS 标头添加到简单和实际 CORS 请求的响应中 因此,浏览器会拒绝它们。Originspring-doc.cn

每个都可以使用基于 URL 模式的映射单独配置。在大多数情况下,应用程序 使用 MVC Java 配置或 XML 命名空间来声明此类映射,这将产生 在传递给所有实例的单个全局映射中。HandlerMappingCorsConfigurationHandlerMappingspring-doc.cn

您可以将 级别的全局 CORS 配置与更多 精细的处理程序级 CORS 配置。例如,带注解的控制器可以使用 类或方法级注释(其他处理程序可以实现)。HandlerMapping@CrossOriginCorsConfigurationSourcespring-doc.cn

组合全局配置和本地配置的规则通常是累加的 — 例如, 所有全球和所有本地源。对于只能使用单个值 accepted,例如 和 ,local 将覆盖 global 值。有关更多详细信息,请参见 CorsConfiguration#combine(CorsConfiguration)。allowCredentialsmaxAgespring-doc.cn

要从源代码中了解更多信息或进行高级自定义,请检查背后的代码:spring-doc.cn

@CrossOrigin

@CrossOrigin 注解支持对带注解的控制器方法进行跨域请求, 如下例所示:spring-doc.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) {
		// ...
	}
}

默认情况下,允许:@CrossOriginspring-doc.cn

allowCredentials默认情况下不启用,因为这会建立信任级别 公开敏感的用户特定信息(例如 cookie 和 CSRF 令牌)和 应仅在适当的情况下使用。启用后,必须 设置为一个或多个特定域(但不是 Special Value )或 该属性可用于匹配一组动态的 Origins。allowOrigins"*"allowOriginPatternsspring-doc.cn

maxAge设置为 30 分钟。spring-doc.cn

@CrossOrigin在类级别也受支持,并且被所有方法继承。 如下例所示:spring-doc.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) {
		// ...
	}

您可以在类级别和方法级别使用 如下例所示:@CrossOriginspring-doc.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) {
		// ...
	}
}

全局配置

除了细粒度的 controller 方法级配置之外,您可能还希望 也定义一些全局 CORS 配置。您可以在任何 .但是,大多数应用程序都使用 MVC Java 配置或 MVC XML 命名空间来执行此操作。CorsConfigurationHandlerMappingspring-doc.cn

默认情况下,全局配置将启用以下功能:spring-doc.cn

allowCredentials默认情况下不启用,因为这会建立信任级别 公开敏感的用户特定信息(例如 cookie 和 CSRF 令牌)和 应仅在适当的情况下使用。启用后,必须 设置为一个或多个特定域(但不是 Special Value )或 该属性可用于匹配一组动态的 Origins。allowOrigins"*"allowOriginPatternsspring-doc.cn

maxAge设置为 30 分钟。spring-doc.cn

Java 配置

要在 MVC Java 配置中启用 CORS,您可以使用回调 如下例所示:CorsRegistryspring-doc.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.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>

CORS 过滤器

您可以通过内置的 CorsFilter 应用 CORS 支持。spring-doc.cn

如果您尝试将 与 Spring Security 一起使用,请记住 Spring Security 内置了对 CORS 的。CorsFilter

要配置过滤器,请将 a 传递给其构造函数,作为 以下示例显示:CorsConfigurationSourcespring-doc.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)