Spring CORS 跨域使用与原理(@CrossOrigin注解,Java配置类方式,xml方式)
出于安全原因,浏览器禁止AJAX调用当前源之外的资源。
跨域资源共享(CORS)是由大多数浏览器实现的W3C规范,它允许您以一种灵活的方式指定授权哪种跨域请求,而不是使用一些不太安全、功能不太强大的hack(如IFrame或JSONP)。
Spring Framework 4.2 GA为CORS提供了一流的开箱即用支持,为我们提供了一种比典型的基于过滤器的解决方案更简单、更强大的配置方式。
一、注解方式使用
1.方法上添加@CrossOrigin注解
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
使用此种方式只会对当前方法生效。
2.Controller上添加@CrossOrigin注解
@CrossOrigin
@RestController
@RequestMapping("/account")
public class AccountController {
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
使用此种方式会对整个Controller生效。
3.@CrossOrigin的两个参数使用
- origins: 允许可访问的域列表
- maxAge:准备响应前的缓存持续的最大时间(以秒为单位)
@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) {
// ...
}
}
这两个参数也可以分开单独使用,如下所示:
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin(origins = "http://domain2.com")
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
4.注意事项
如果有正在使用Spring Security,需要在Spring Security中启用CORS,以允许它利用Spring MVC定义的配置。如下所示:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
二、CORS全局配置使用
除了细粒度的、基于注释的配置之外,我们还可以自定义一些全局CORS配置。类似于使用过滤器,但可以在Spring MVC中声明,并结合细粒度的@CrossOrigin配置。默认情况下,所有的origin和GET、HEAD和POST方法都可以使用。
1.Java配置类方式
使用非常简单,如下所示:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
如果是使用的Spring Boot,建议只声明一个WebMvcConfigurer bean,如下所示:
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
除此之外,我们还可以自定义更多的其他属性,比如将CORS配置应用于特定的路径模式:
@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);
}
同样,此处我们要注意Spring Security使用的情况,具体实现参考注解使用中的实现。
2.XML配置文件方式
当然,我们也可以使用xml配置文件的方式来进行全局配置,如下所示:
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
同样也可以在xml中自定义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>
三、原理解释
CORS请求(包括带有OPTIONS方法的飞行前请求)被自动分派给已注册的各种HandlerMappings。它们处理CORS预飞行请求,并通过CorsProcessor实现(默认为DefaultCorsProcessor)拦截CORS简单和实际请求,以便添加相关的CORS响应头(如Access-Control-Allow-Origin)。CorsConfiguration允许您指定应该如何处理CORS请求:allowed origins, headers, methods, etc等。
可以通过多种方式提供,如:
- AbstractHandlerMapping#setCorsConfiguration()允许在路径模式(如/api/)上指定多个CorsConfiguration映射的Map
- 子类可以通过重写AbstractHandlerMapping#getCorsConfiguration(Object, HttpServletRequest)方法来提供他们自己的CorsConfiguration
- 处理程序可以实现CorsConfigurationSource接口(就像ResourceHttpRequestHandler现在做的那样),以便为每个请求提供CorsConfiguration。
除此之外,还可以使用基于CORS的过滤器支持,作为上述其他方法的替代方案,Spring Framework还提供了CorsFilter。在这种情况下,不使用@CrossOrigin或WebMvcConfigurer# addcorsmapping (CorsRegistry),我们可以像下面这样在Spring Boot中声明过滤器:
@Configuration
public class MyConfiguration {
@Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://domain1.com");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
以上内容参考自Spring官方文档:https://spring.io/blog/2015/06/08/cors-support-in-spring-framework