在研发过程中,跨域资源共享会经常碰到,使用CORS(英文全称:Cross-Origin Resource Sharing 即我们常说的跨域资源共享)可以帮助我们快速实现跨域访问,只需在服务端进行相应的授权配置,无需在前端添加额外设置,相比传统的JSONP跨域更安全和便捷。
相关术语理解
1.origin:理解为源,就是协议、域名和端口,如果请求地址的协议、域名和端口都相同则属于同源
例如:
http://www.abc.com:80和 http://www.abc.com:80/text.html --同源
http://www.abc.com:80和 http://www.abc.com:8080/text.html --端口号不同,不属于同源
http://www.abc.com:80和 https://www.abc.com:80/text.html --协议不同,不属于同源
http://www.abc.com:80和 http://www.def.com:80/ --域名不同,不属于同源
2.什么是同源策略
浏览器采用是同源策略(保证浏览器的安全),禁止浏览器加载或执行与当前网页资源来源不同的域的任何脚本
情景:
比如一个恶意网站的页面通过iframe嵌入了第三方网站的登录页面(二者不同源),如果没有同源限制,恶意网页上的javascript脚本就可以在用户登录的时候获取第三方网站的用户名和密码。
浏览器中有哪些不受同源限制呢?
<script>、<img>、<iframe>、<link>这些包含 src 属性的标签可以加载跨域资源。但浏览器限制了JavaScript的权限使其不能读、写加载的内容。
3.跨域
跨域是指从一个域的网页去请求另一个域的资源。比如从http://www.abc.com/ 页面去请求 http://www.def.com 的资源。
SpringBoot中的跨域授权方式
a.返回新的CorsFilter
@Configuration
public class CorsConfiger {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfig()); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
private CorsConfiguration corsConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
if(RString.isBlank(AppResource.getProperty("AllowedOrigins"))){
corsConfiguration.addAllowedOrigin("*");
}else{
corsConfiguration.setAllowedOrigins(Arrays.asList(AppResource.getProperty("AllowedOrigins").split(",")));
}
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
}
b.重写WebMvcConfigurer
说明:spring boot2.0之后在构造spring配置文件时建议推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport ,经测试实现WebMvcConfigurer是没问题,但继承WebMvcConfigurationSupport类是会导致自动配置失效的。
@Configuration
public class CorsConfig extends WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT","PATCH")
.maxAge(3600);
}
}
c.使用注解(@CrossOrigin)
@CrossOrigin(origins=“http://test.com”,maxAge=3600)
参数解释:
origins:允许可访问的域列表
maxAge:准备响应前的缓存持续的最大时间(以秒为单位),默认30分钟
注解@CrossOrigin不起作用的原因
1.是springMVC的版本要在4.2或以上版本才支持@CrossOrigin
2.在Controller注解上方添加@CrossOrigin注解后,仍然出现跨域问题,解决方案之一就是,在@RequestMapping注解中没有指定Get、Post方式,具体指定后,问题解决
例如:
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
//...
}
}
4.Request Headers(请求头)如下:
Origin:表示跨域请求的原始域。
Access-Control-Request-Method:表示跨域请求的方式。(如GET/POST)
Access-Control-Request-Headers:表示跨域请求的请求头信息。
5.Response headers(响应头 )说明如下:
Access-Control-Allow-Origin:表示允许哪些原始域进行跨域访问。(字符数组)
Access-Control-Allow-Credentials:表示是否允许客户端获取用户凭据。(布尔类型)
使用场景:例如现在从浏览器发起跨域请求,并且要附带Cookie信息给服务器。则必须具备两个条件:
1. 浏览器端:发送AJAX请求前需设置通信对象XHR的withCredentials 属性为true。
2.服务器端:设置Access-Control-Allow-Credentials为true。两个条件缺一不可,否则即使服务器同意发送Cookie,浏览器也无法获取。
Access-Control-Allow-Methods:表示跨域请求的方式的允许范围。(例如只授权GET/POST)
Access-Control-Allow-Headers:表示跨域请求的头部的允许范围。
Access-Control-Expose-Headers:表示暴露哪些头部信息,并提供给客户端。(因为基于安全考虑,如果没有设置额外的暴露,跨域的通信对象XMLHttpRequest只能获取标准的头部信息)
Access-Control-Max-Age:表示预检请求 [Preflight Request] 的最大缓存时间。
a.例如:设置响应头(HttpServletResponse)
使用HttpServletResponse对象添加响应头(Access-Control-Allow-Origin)来授权原始域,这里Origin的值也可以设置为”*” ,表示全部放行。
@RequestMapping("/hello")
@ResponseBody
public String hello(HttpServletResponse response){
response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
return "Hello World";
}