一、同源策略
同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是 JSONP,JSONP 虽然能解决跨域但是有一个很大的局限性,那就是只支持 GET 请求,不支持其他类型的请求,而 CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个 W3C 标准,它是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是 JSONP 模式的现代版。在 Spring 框架中,对于 CORS 也提供了相应的解决方案, SpringBoot 中如何实现 CORS。
二、如何出现
启动两个 SpringBoot 项目,分别以 8080 和 8081 端口启动,在其中一个写上如下的 Controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @RestController public class HelloController {
@PostMapping("/hello") public String hello1() { return "get hello"; }
@GetMapping("/hello") public String hello2() { return "post hello"; }
}
|
在另一个中写入一个静态页面:
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 26
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="jquery-3.5.1.js"></script> </head> <body> <div id="app"></div> <input type="button" onclick="btnClick()" value="get_button"> <input type="button" onclick="btnClick2()" value="post_button"> <script> function btnClick() { $.get('http://localhost:8080/hello', function (msg) { $("#app").html(msg); }); }
function btnClick2() { $.post('http://localhost:8080/hello', function (msg) { $("#app").html(msg); }); } </script> </body> </html>
|
注:记得引入 Jquery
在 http://localhost:8081/hello.html 点击任何请求:

可以看到此时已经发生跨域问题
三、解决方案
从后端解决,修改 Controller 为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @RestController public class HelloController {
@CrossOrigin(origins = "http://localhost:8081") @PostMapping("/hello") public String hello1() { return "post hello"; }
@CrossOrigin(value = "http://localhost:8081") @GetMapping("/hello") public String hello2() { return "get hello"; }
}
|
其中 origins 与 value 效果一样,看源码可以知道它们互相成为对方的别名
此时已经不会出现跨域问题

四、加强版解决
此时,在每一个类或者方法上都使用这个注解,法外狂徒张三都觉得这个太麻烦了
只需要配置一个实现 WebMvcConfigurer 配置类,如下:
1 2 3 4 5 6 7 8
| public class CORSConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("http://localhost:8081") .allowedMethods("*") .allowedHeaders("*"); } }
|
注:/** 表示本应用的所有方法都会去处理跨域请求;allowedMethods 表示允许通过的请求数;allowedHeaders 则表示允许的请求头。
五、安全问题
出现了一个王八老本行的问题:通过 Ajax 发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是 CSRF(Cross-site request forgery)跨站请求伪造。
一句话:利用我们还在登录的状态,即 Cookie 有效,打开一个正常网站,而这个网站上可能有一个非正常操作 ( 图片,链接等) ,那你就可能已经被攻击。
在信息安全中,我们防御 CSRF 的方法主要是增加 Token,这也是现在大多数防御 CSRF 的方式。