Spring Framework 中文文档

4.3.21.RELEASE

27. CORS 支持

27.1 简介

出于安全原因,浏览器禁止 AJAX calls 驻留在当前源之外的资源。例如,当您在一个标签中查看银行帐户时,可以在另一个标签中打开 evil.com 网站。来自 evil.com 的脚本无法使用您的凭据向您的银行 API(e.g. ,从您的帐户中提取资金!)发出 AJAX 请求。

Cross-origin 资源共享(CORS)是由大多数浏览器实现的W3C 规范,它允许您以灵活的方式指定授权哪种类型的跨域请求,而不是使用一些安全性较低且功能较弱的黑客,如 IFRAME 或 JSONP。

从 Spring Framework 4.2 开始,CORS 支持开箱即用。 CORS 请求(包括带有 OPTIONS 方法的预检)会自动分派到各个已注册的HandlerMapping。它们处理 CORS 预检请求并拦截 CORS 简单和实际请求,这要归功于 order 中的CorsProcessor implementation(默认为DefaultCorsProcessor),以根据您提供的 CORS configuration 添加相关的 CORS 响应 headers(如Access-Control-Allow-Origin)。

由于自动调度 CORS 请求,因此不需要来更改DispatcherServlet dispatchOptionsRequest init 参数 value;使用其默认的 value(false)是推荐的方法。

27.2 控制器方法 CORS configuration

您可以在 order 中为@RequestMapping带注释的处理程序方法添加@CrossOrigin annotation 以在其上启用 CORS。默认情况下@CrossOrigin允许@RequestMapping annotation 中指定的所有原点和 HTTP 方法:

@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin
	@RequestMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

也可以为整个控制器启用 CORS:

@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@RequestMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

在上面的示例中,为retrieve()remove()处理程序方法启用了 CORS 支持,您还可以看到如何使用@CrossOrigin属性自定义 CORS configuration。

您甚至可以同时使用 controller-level 和 method-level CORS 配置;然后,Spring 将组合来自两个 annotations 的属性以创建合并的 CORS configuration。

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin("http://domain2.com")
	@RequestMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

27.3 Global CORS configuration

除了 fine-grained,annotation-based configuration 之外,您可能还想定义一些 global CORS configuration。这与使用过滤器类似,但可以在 Spring MVC 中声明,并与 fine-grained @CrossOrigin configuration 结合使用。默认情况下,允许所有原点和GETHEADPOST方法。

27.3.1 JavaConfig

为整个 application 启用 CORS 非常简单:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/**");
	}
}

您可以轻松更改任何 properties,并仅将此 CORS configuration 应用于特定路径 pattern:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry.addMapping("/api/**")
			.allowedOrigins("http://domain2.com")
			.allowedMethods("PUT", "DELETE")
			.allowedHeaders("header1", "header2", "header3")
			.exposedHeaders("header1", "header2")
			.allowCredentials(false).maxAge(3600);
	}
}

27.3.2 XML 命名空间

以下最小的 XML configuration 为/** path pattern 启用 CORS,其默认 properties 与上述 JavaConfig 示例相同:

<mvc:cors>
	<mvc:mapping path="/**" />
</mvc:cors>

也可以使用自定义的 properties 声明多个 CORS 映射:

<mvc:cors>

	<mvc:mapping path="/api/**"
		allowed-origins="http://domain1.com, http://domain2.com"
		allowed-methods="GET, PUT"
		allowed-headers="header1, header2, header3"
		exposed-headers="header1, header2" allow-credentials="false"
		max-age="123" />

	<mvc:mapping path="/resources/**"
		allowed-origins="http://domain1.com" />

</mvc:cors>

27.4 高级自定义

CorsConfiguration允许您指定如何处理 CORS 请求:允许的来源,headers,方法等。它可以以各种方式提供:

27.5 基于过滤器的 CORS 支持

为了支持 CORS 与安全框架(如Spring Security),或与其他不支持本机 CORS 的 libraries,Spring Framework 还提供CorsFilter。而不是使用@CrossOriginWebMvcConfigurer#addCorsMappings(CorsRegistry),您需要注册定义如下的自定义过滤器:

import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

public class MyCorsFilter extends CorsFilter {

	public MyCorsFilter() {
		super(configurationSource());
	}

	private static UrlBasedCorsConfigurationSource configurationSource() {
		CorsConfiguration config = new CorsConfiguration();
		config.setAllowCredentials(true);
		config.addAllowedOrigin("http://domain1.com");
		config.addAllowedHeader("*");
		config.addAllowedMethod("*");
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", config);
		return source;
	}
}

您需要确保在其他过滤器之前订购CorsFilter,请参阅这篇博文,了解如何相应地配置 Spring Boot。

Updated at: 6 months ago
26.4.19. 测试Table of contentVII. Integration