0%

跨域问题.md

跨域问题。

什么是跨域

浏览器出于安全考虑,限制了JS发起跨站请求,使用XHR对象发起请求必须遵循同源策略(SOP:Same Origin Policy),跨站请求会被浏览器阻止。

什么是CORS

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

以下内容引用自 阮一峰

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

解决方案

方法级别或者类级别跨域

当 应用中,仅有少量rest接口的时候,使用 CrossOrigin 注解 方式非常简单,只需在 controller 上添加该注解即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RestController
public class HandlerScanController {

@CrossOrigin(
allowCredentials="true",
allowedHeaders="*",
methods=
{RequestMethod.GET,
RequestMethod.POST,
RequestMethod.DELETE,
RequestMethod.OPTIONS,
RequestMethod.HEAD,
RequestMethod.PUT,
RequestMethod.PATCH},
origins="*")
@PostMapping("/confirm")
public Response handler(@RequestBody Request json){
return null;
}
}
  • @CrossOrigin: 可以添加到 method 和 class 上
  • origins: 允许的来源列表. 他的值放置在HTTP协议的响应header的Access-Control-Allow-Origin
  • allowedHeaders: 实际请求期间可以使用的请求标头列表. 值用于预检的响应header Access-Control-Allow-Headers
  • methods: 支持的HTTP请求方法列表。 如果未定义,则使用由RequestMapping注释定义的方法
  • exposedHeaders: 浏览器允许客户端访问的响应头列表。 在实际响应报头Access-Control-Expose-Headers中设置值
  • allowCredentials: 它确定浏览器是否应该包含与请求相关的任何cookie
  • maxAge: 预响应的高速缓存持续时间的最大时间(以秒为单位)。 值在标题Access-Control-Max-Age中设置。

WebMvcConfigurer 全局跨域

对应不同的技术选型,跨域配置是不同的。全局的接口都支持跨域访问,容易引起安全性问题。

下面列举的配置方案 尽量不要共用。

SpringMvc 项目

对于 SpringMvc 项目,只需在 WebMvcConfigurerAdapter实现类里重写 addCorsMappings() 方法即可。

1
2
3
4
5
6
7
8
9
10
@Configuration
@EnableWebMvc
public class CorsConfiguration extends WebMvcConfigurerAdapter
{
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("GET", "POST");
}
}

Spring boot

声明一个 WebMvcConfigurer 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class CorsConfiguration
{
@Bean
public WebMvcConfigurer corsConfigurer()
{
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}

Spring Security

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
//other config
}

@Bean
CorsConfigurationSource corsConfigurationSource()
{
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}

使用 filter

这种方案的使用场景跟上面的方案类似,只不过换成使用Filter的方式实现。

CorsFilter 为 org.springframework.web.filter.CorsFilter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test{

@Bean
public CorsFilter corsFilter() {

final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.addAllowedMethod("OPTIONS");// 允许提交请求的方法,*表示全部允许
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");// 允许Get的请求方法
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);

return new CorsFilter(source);
}

}

参考

跨域问题的五种解决方案
spring自带-rest-Service-cors
spring 跨域支持
阮一峰-CORS详解