CORS 跨域共享
跨源资源共享(Cross-origin resource sharing, CORS)是由大多数浏览器实现的W3C规范,它允许您以灵活的方式指定哪种跨域请求被授权,而不是使用一些不太安全、功能不太强大的方法,比如IFRAME或JSONP。
参考之前的文章:通信—跨域资源共享
Spring BOOT
从4.2开始,Spring MVC已支持CORS。
@CrossOrigin
在Spring Boot中使用带有@CrossOrigin注释的controller方法CORS配置,不需要任何特定的配置。
@CrossOrigin注解可以在类上使用,也可以在方法上使用,如:
@CrossOrigin(origins = "http://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) { // ... } }
常用的属性有2个,分别是origins和maxAge,下面分别解释下:
- origins 是一个字符串数组的类型(String []),用于表示那些域名可以访问此接口/映射。多个域名之间用逗号“,”隔开,如果想向所有网址开放,可以直接填写星号“*”。
- maxAge 还没有找到官方的说明,其他开发者解释为“预请求的结果的有效期”,即COOKIE的有效期,单位是秒。
如果只在方法上或者类上使用@CrossOrigin注解,则默认该映射接受所有的网站发送过来的请求、接受所有类型的http请求和接受所有的不同内容的头部信息(Header),如:
@RestController @RequestMapping("/account") public class AccountController { @CrossOrigin @GetMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @DeleteMapping("/{id}") public void remove(@PathVariable Long id) { // ... } }
@CrossOrigin可以同时在类上、方法上同时使用,来控制不同网站访问不同的映射,如:
@CrossOrigin(maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("http://domain2.com") @GetMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @DeleteMapping("/{id}") public void remove(@PathVariable Long id) { // ... } }
remove方法可以被所有网站的访问,retrieve方法只接受http://domain2.com网站发送的请求。
全局CORS配置
全局CORS配置可以通过注册一个WebMvcConfigurer bean并使用自定义的addcorsmapping (CorsRegistry)方法来定义,如:
@Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") .maxAge(3600) .allowCredentials(true); } }
拦截器
另外,还可以通过添加 Filter 的方式,配置 CORS 规则,并手动指定对哪些接口有效。
@Bean public FilterRegistrationBean corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("http://localhost:9000"); config.addAllowedOrigin("null"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); // CORS 配置对所有接口都有效 FilterRegistrationBean bean = newFilterRegistrationBean(new CorsFilter(source)); bean.setOrder(0); return bean; }
原理剖析
无论是通过哪种方式配置 CORS
,其实都是在构造 CorsConfiguration
。 一个 CORS
配置用一个 CorsConfiguration
类来表示,它的定义如下:
public class CorsConfiguration { private List<String> allowedOrigins; private List<String> allowedMethods; private List<String> allowedHeaders; private List<String> exposedHeaders; private Boolean allowCredentials; private Long maxAge; }
Spring
中对 CORS
规则的校验,都是通过委托给 DefaultCorsProcessor
实现的。
DefaultCorsProcessor
处理过程如下:
- 判断依据是
Header
中是否包含Origin
。如果包含则说明为CORS
请求,转到 2;否则,说明不是CORS
请求,不作任何处理。 - 判断
response
的Header
是否已经包含Access-Control-Allow-Origin
,如果包含,证明已经被处理过了, 转到 3,否则不再处理。 - 判断是否同源,如果是则转交给负责该请求的类处理
- 是否配置了
CORS
规则,如果没有配置,且是预检请求,则拒绝该请求,如果没有配置,且不是预检请求,则交给负责该请求的类处理。如果配置了,则对该请求进行校验。
校验就是根据 CorsConfiguration
这个类的配置进行判断:
- 判断
origin
是否合法 - 判断
method
是否合法 - 判断
header
是否合法 - 如果全部合法,则在
response header
中添加响应的字段,并交给负责该请求的类处理,如果不合法,则拒绝该请求。
参考: