3 CORS支持
3.1 介绍
出于安全考虑,浏览器禁止对当前源之外的资源进行AJAX调用。例如,当你在一个标签页检查你的银行账户时,你可以在另一个标签页打开evil.com的网站。在evil.com中的脚本不能使用你的凭据来通过AJAX请求访问你的银行API(例如,从你的银行取款!)。
跨域资源共享(Cross-origin resource sharing)(CORS)是W3C的标准,大部分的浏览器都实现了这个标准来让你可以灵活地指定什么样的跨域请求是被授权的,而不用使用IFRAME或JSONP这些不太安全和功能不强的黑客技术。
从Spring Framework 4.2起,CORS就支持开箱即用。CORS请求(包括一个预检请求OPTIONS方法)自动分发到各个注册的HandlerMapping
中。由于CorsProcessor的实现(默认是DefaultCorsProcessor),它们处理CORS预检请求,并拦截CORS的简单而实际请求,以便根据你提供的CORS配置添加相关的CORS响应头(如Access-Control-Allow-Origin
)。
由于CORS请求是自动分发的,你不需要改变
DispatcherServlet
dispatchOptionsRequest
的初始参数值;推荐的方式是使用它的默认值(false)。
3.2 控制器方法CORS配置
你可以在你的@RequestMapping
注解处理方法上添加一个@CrossOrigin
注解来开启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将组合两个注解的属性来创建一个组合的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) {
// ...
}
}
3.3 全局CORS配置
除了基于注解的细粒度配置,你也可能想要定义一些全局的CORS配置。这个与使用过滤器类似,但是可以在Spring MVC中声明跟加上@CrossOrigin
的细粒度配置。默认是允许所有的源跟GET
,HEAD
和POST
方法。
3.3.1 JavaConfig
整个应用开启CORS的例子如下:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
你可以轻松地改变任何属性,也可以将CORS配置指定到特殊的路径模式:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@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);
}
}
3.3.2 XML命名空间
下面的最小XML配置可以在/**
路径模式下开启CORS,具有跟前文提到的JavaConfig一样的缺省属性,例子:
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
它还可以用定制的属性来指定多个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>
3.4 高级定制
CorsConfiguration允许你指定CORS请求如何被处理:允许的源,头信息,方法等等。它可以以多种方式提供:
-
AbstractHandlerMapping#setCorsConfiguration()
允许通过一个有一些CorsConfiguration实例的Map
来指定映射到如/api/**
的路径模式上。 - 子类也可以通过重写
AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest)
方法来提供它们的CorsConfiguration
。 - 为了给每个请求提供一个CorsConfiguration实例,处理器可以实现
CorsConfigurationSource
接口(如ResourceHttpRequestHandler现在做的)。
3.5 基于过滤器的CORS支持
为了实现如Spring Security的基于过滤器的安全框架去支持CORS,或其他原生不支持CORS的类库,Spring框架也提供了CorsFilter。而不是使用@CrossOrigin
或WebMvcConfigurer#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的这篇博客。
【译者注】
原文:http://docs.spring.io/spring/docs/5.0.0.RC1/spring-framework-reference/web.html#cors
看这篇文章之前,建议看一下阮一峰写的关于CORS的文章
欢迎批评指正