springboot允许跨域注解_SpringBoot中三种跨域场景总结松哥周末抽空给 Spring Security 系列也录制了⼀套视频,⽬录如下:
感兴趣的⼩伙伴戳这⾥-->Spring Boot+Vue+微⼈事视频教程
跨域这个问题松哥之前写过⽂章,但是最近收到⼩伙伴们的⼀些问题,让我发现之前的总结不够全⾯,因此打算再写⼀篇⽂章,来和⼤家分享⼀下 Spring Boot 中的跨域问题。
这次我把 Spring Boot 中的跨域问题分为了三个场景:
普通跨域
Spring Security 跨域
OAuth2 跨域
分为三种并⾮多此⼀举,主要是因为这三种场景的配置都不太⼀样,⽽这三种场景⼜都是⾮常常见的场景,所以这⾥和⼤家再来专门分享下。
1.什么是跨域
很多⼈对跨域有⼀种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略。
同源策略是由 Netscape 提出的⼀个著名的安全策略,它是浏览器最核⼼也最基本的安全功能,现在所有⽀持 JavaScript 的浏览器都会使⽤这个策略。所谓同源是指协议、域名以及端⼝要相同。
同源策略是基于安全⽅⾯的考虑提出来的,这个策略本⾝没问题,但是我们在实际开发中,由于各种原因⼜经常有跨域的需求,传统的跨域⽅案是 JSONP,JSONP 虽然能解决跨域但是有⼀个很⼤的局限性,那就是只⽀持 GET 请求,不⽀持其他类型的请求,在 RESTful 时代这⼏乎就没什么⽤。
⽽今天我们说的 CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是⼀个 W3C 标准,它是⼀份浏览器技术的规范,提供了 Web 服务从不同⽹域传来沙盒脚本的⽅法,以避开浏览器的同源策略,这是 JSONP 模式的现代版。
在 Spring 框架中,对于 CORS 也提供了相应的解决⽅案,在 Spring Boot 中,这⼀⽅案得倒了简化,⽆论是单纯的跨域,还是结合Spring Security 之后的跨域,都变得⾮常容易了。
2.解决⽅案
⾸先创建两个普通的 Spring Boot 项⽬,这个就不⽤我多说,第⼀个命名为 provider 提供服务,第⼆个命名为 consumer 消费服务,第⼀个配置端⼝为 8080,第⼆个配置配置为 8081,然后在 provider 上提供两个 hello 接⼝,⼀个 get,⼀个 post,如下:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@PostMapping("/hello")
public String hello2() {
return "post hello";
}
}
在 consumer 的 resources/static ⽬录下创建⼀个 html ⽂件,发送⼀个简单的 ajax 请求,如下:
<div id="app">div>
<input type="button" onclick="btnClick()" value="get_button">
<input type="button" onclick="btnClick2()" value="post_button">
<script>function btnClick() {
$.get('localhost:8080/hello', function (msg) {
$("#app").html(msg);
ssm框架实现登录功能
});
}function btnClick2() {
$.post('localhost:8080/hello', function (msg) {
$("#app").html(msg);
});
}script>
然后分别启动两个项⽬,发送请求按钮,观察浏览器控制台如下:
Access to XMLHttpRequest at 'localhost:8080/hello' from origin 'localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-O 可以看到,由于同源策略的限制,请求⽆法发送成功。
使⽤ CORS 可以在前端代码不做任何修改的情况下,实现跨域,那么接下来看看在 provider 中如何配置。⾸先可以通过 @CrossOrigin
注解配置某⼀个⽅法接受某⼀个域的请求,如下:
@RestController
public class HelloController {
@CrossOrigin(value = "localhost:8081")
@GetMapping("/hello")
public String hello() {
return "hello";
}
@CrossOrigin(value = "localhost:8081")
@PostMapping("/hello")
public String hello2() {
return "post hello";
}
}
此时观察浏览器请求⽹络控制台,可以看到响应头中多了如下信息:
provider 上,每⼀个⽅法上都去加注解未免太⿇烦了,有的⼩伙伴想到可以讲注解直接加在 Controller 上,不过每个 Controller 都要加还是⿇烦,在 Spring Boot 中,还可以通过全局配置⼀次性解决这个问题,全局配置只需要在 SpringMVC 的配置类中重写addCorsMappings ⽅法即可,如下:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("localhost:8081")
.allowedMethods("*")
.allowedHeaders("*");
}
}
/** 表⽰本应⽤的所有⽅法都会去处理跨域请求,allowedMethods 表⽰允许通过的请求数,allowedHeaders 则表⽰允许的请求头。经过这样的配置之后,就不必在每个⽅法上单独配置跨域了。
2.1 存在的问题
了解了整个 CORS 的⼯作过程之后,我们通过 Ajax 发送跨域请求,虽然⽤户体验提⾼了,但是也有潜在的威胁存在,常见的就是
CSRF(Cross-site request forgery)跨站请求伪造。跨站请求伪造也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF,是⼀种挟制⽤户在当前已登录的 Web 应⽤程序上执⾏⾮本意的操作的攻击⽅法。
关于 CSRF 攻击的具体介绍和防御办法,⼤家可以参考松哥之前的⽂章,这⾥就不重复介绍了:
松哥⼿把⼿教你在 SpringBoot 中防御 CSRF 攻击!so easy!
要学就学透彻!Spring Security 中 CSRF 防御源码解析
3.SpringSecurity
如果使⽤了 Spring Security,上⾯的跨域配置会失效,因为请求被 Spring Security 拦截了。
当引⼊了 Spring Security 的时候,我们有两种办法开启 Spring Security 对跨域的⽀持。
3.1 ⽅式⼀
⽅式⼀就是在上⼀⼩节的基础上,添加 Spring Security 对于 CORS 的⽀持,只需要添加如下配置即可:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.httpBasic()
.and()
.cors()
.and()
.csrf()
.disable();
}
}
⼀个 .cors 就开启了 Spring Security 对 CORS 的⽀持。
3.2 ⽅式⼆
⽅式⼆则是去除第⼆⼩节的跨域配置,直接在 Spring Security 中做全局配置,如下:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.
permitAll()
.and()
.httpBasic()
.and()
.cors()
.configurationSource(corsConfigurationSource())
.and()
.csrf()
.disable();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setMaxAge(Duration.ofHours(1));
return source;
}
}
通过 CorsConfigurationSource 实例对跨域信息作出详细配置,例如允许的请求来源、允许的请求⽅法、允许通过的请求头、探测请求的有效期、需要处理的路径等等。
使⽤这种⽅式就可以去掉第⼆⼩节的跨域配置了。
4.OAuth2
还有⼀种情况就是 OAuth2 允许跨域,如果⽤户要访问 OAuth2 端点,例如 /oauth/token ,出现了跨域该怎么配置呢?
这个解决⽅案松哥在之前的 【⽤ Swagger 测试接⼝,怎么在请求头中携带 Token?】 ⼀⽂中已经有过介绍,主要是配置⼀个CorsFilter,⼤家可以参考该篇⽂章,我这⾥就把核⼼配置类列出来:
@Configuration
public class GlobalCorsConfiguration {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
然后在 SecurityConfig 中开启跨域⽀持:
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
...
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers(HttpMethod.OPTIONS, "/oauth/**")
.and()
.
csrf().disable().formLogin()
.and()
.cors();
}
}
5.⼩结
好啦,今天主要和⼩伙伴们总结了⼀下 Spring Boot 中三种跨域的场景,不知道⼤家有没有 GET 到呢?如果觉得有收获,记得点个在看⿎励下松哥哦~
今⽇⼲货

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。