27. CORS Support

27.1 Introduction

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

跨域资源共享(CORS)是由most browsers实现的W3C specification,它使您可以灵活地指定对哪种跨域请求进行授权,而不必使用诸如 IFRAME 或 JSONP 之类的安全性较低且功能较弱的黑客。

从 Spring Framework 4.2 开始,开箱即用地支持 CORS。 CORS 请求(使用 OPTIONS 方法包括预检)被自动分派到各个已注册的HandlerMapping。由于使用了CorsProcessor实现(默认为DefaultCorsProcessor),它们可以处理 CORS 预检请求并拦截 CORS 简单和实际的请求,以便根据您提供的 CORS 配置添加相关的 CORS 响应 Headers(如Access-Control-Allow-Origin)。

Note

由于 CORS 请求是自动分派的,因此您 无需 更改DispatcherServlet dispatchOptionsRequest初始化参数值;建议使用其默认值(false)。

27.2 控制器方法 CORS 配置

您可以将@CrossOriginComments 添加到带有@RequestMappingComments 的处理程序方法中,以便在其上启用 CORS。默认情况下,@CrossOrigin允许所有来源和@RequestMapping注解中指定的 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 配置。

您甚至可以同时使用控制器级别和方法级别的 CORS 配置。然后,Spring 将结合两个 Comments 中的属性来创建合并的 CORS 配置。

@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 全局 CORS 配置

除了基于 Comments 的细粒度配置之外,您可能还需要定义一些全局 CORS 配置。这类似于使用过滤器,但是可以在 Spring MVC 中声明并与细粒度的@CrossOrigin配置结合使用。默认情况下,所有原点以及GETHEADPOST方法都是允许的。

27.3.1 JavaConfig

为整个应用程序启用 CORS 很简单:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

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

您可以轻松更改任何属性,以及仅将此 CORS 配置应用于特定的路径模式:

@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 配置使/**路径模式的 CORS 具有与上述 JavaConfig 示例相同的默认属性:

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

也可以使用自定义属性声明几个 CORSMap:

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

为了使用诸如Spring Security之类的基于过滤器的安全框架来支持 CORS,或者使用其他本机不支持 CORS 的库来支持 CORS,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;
	}
}

您需要确保在其他过滤器之前 Order 了CorsFilter,有关如何相应配置 Spring Boot 的信息,请参见此博客文章