本文参考自江南一点雨的Spring Boot+Vue系列视频教程第 3 章,详情参加【Spring Boot+Vue系列视频教程】
跨域问题是开发中常见的问题!下面先介绍什么是跨域问题,也是我看一篇好文章学到的。
看看你是怎么给妹子解释跨域的??
小美:geigei,geigei为什么会有跨域问题?
你: 因为浏览器的同源策略导致了跨域.
-------------------------------------------------------------------------
小美:浏览器为什么要搞这么麻烦的同源策略? 5555~
你: 同源策略限制了从同一个源加载的文档或脚本 如何与 来自另一个源的资源进行交互。
这是一个用于隔离潜在恶意文件的重要安全机制。
--------------------------------------------------------------------------
小美:没看懂,好像说是为了安全,就像哥哥.....
你:咳咳!浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询。
---------------------------------------------------------------------------
小美:那如果不..抱歉哥哥。我说的是如果没有同源策略会怎样呢?
你:首先没有同源策略的接口请求:cookie你应该知道吧?
假如你登录某购物网站,如果你请求了接口进行登录,服务端验证通过后会在响应头加入Set-Cookie字段
然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中。
然后你在购物网站推荐里不小心搜了一个“透“字,你便熟练地打开了另一个小网站
但是这个小网站很坏,背地里居然向你刚才的购物网站发送请求。
由于没有同源策略,这个小网站就登录了你的账号,为所欲为了一翻! 这就是传说中的CSRF攻击
没有同源策略限制的Dom查询:有天早上你还没睡醒,突然接到短信说你中了500w
你赶紧点开连接,输入了银行密码查询,事后才发现原来是钓鱼网站。
如果没有同源策略,钓鱼网站就可以拿到别的网站的Dom
天上哪有馅饼,都是为了你兜里的两块五毛钱啊!!!!
------------------------------------------------------------------------------
小美:好可怕好可怕,浏览器这个同源策略还是很好的呢,这么看来
你 : 邪魅一笑,但是!只要我是正人君子是可以实现跨域的!打开方式正确:
同源策略限制下接口请求的正确打开方式:1.JSONP 2.空iframe加form 3.CORS 4.代理
同源策略限制下Dom查询的正确打开方式:1.postMessage 2.document.domain 3.canvas操作图片的跨域问题
--------------------------------------------------------------------------------
小美:哥哥你能具体说说吗??对了去我家教教我,我家没人...
你 : 虽然哥哥是正人君子,但是我很乐意传授知识
本文只传授一波CORS吧!这也是现在主流的跨域方式
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
看名字就知道这是处理跨域问题的标准做法。
CORS有两种请求,简单请求和非简单请求。
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
总结:
所谓同源是指协议、域名以及端口要相同。同源策略是基于安全方面的考虑提出来的,这个策略本身没问题,但是我们在实际开发中,由于各种原因又经常有跨域的需求,传统的跨域方案是JSONP,JSONP虽然能解决跨域但是有一个很大的局限性,那就是只支持GET请求,不支持其他类型的请求,而今天我们说的CORS(跨域源资源共享)(CORS,Cross-origin resource sharing)是一个W3C标准,它是一份浏览器技术的规范,提供了Web服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,这是JSONP模式的现代版。
域:协议+域名/IP+端口 有一个不一样就是跨域了,同源策略就只能请求相同域中的资源。
域检请求,当请求不是简单请求的时候,在发送之前会先检查服务端是否支持要发送的请求,服务端会告诉客户端支持什么请求。
====================================================================
在Spring框架中,对于CORS也提供了相应的解决方案,今天我们就来看看SpringBoot中如何实现CORS。
SpringBoot中如何实现CORS。
案例:
需求:两个不同的项目同时运行(端口号不一样),跨域了,如何让第二个项目直接访问到第一个项目中的资源?
环境搭建:
- 有两个工程cors01和cors02,一个提供服务一个消费服务
- cors01 端口号:8080 cors02端口号:8088
- 在cors01 提供两个hello接口,一个get,一个post
- 在cors02 中创建一个html,发送一个简单的Ajax请求
同时运行,点击请求按钮观察。
编码:cors01(提供服务)
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello";
}
@PostMapping("/hello")
public String hello2() {
return "post hello";
}
}
编码:cors02(消费服务)
-
修改端口
server.port=8088
-
发送简单的Ajax请求
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>消费服务</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.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> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>消费服务</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.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>
未处理跨域时:
如何实现跨域呢??
1.@CrossOrigin注解配置某一个方法接受某一个域的请求
@CrossOrigin中的值表示允许来自对应值的接口访问
@RestController
public class HelloController {
@CrossOrigin(value = "http://localhost:8088")
@GetMapping("/hello")
public String hello() {
return "hello";
}
@PostMapping("/hello")
@CrossOrigin(value = "http://localhost:8088")
public String hello2() {
return "post hello";
}
}
测试:
@CrossOrigin( )中还有好多跨域先关的设置,小伙伴们可以自行查看源码。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
/** @deprecated */
@Deprecated
String[] DEFAULT_ORIGINS = new String[]{"*"};
/** @deprecated */
@Deprecated
String[] DEFAULT_ALLOWED_HEADERS = new String[]{"*"};
/** @deprecated */
@Deprecated
boolean DEFAULT_ALLOW_CREDENTIALS = false;
/** @deprecated */
@Deprecated
long DEFAULT_MAX_AGE = 1800L;
@AliasFor("origins")
String[] value() default {};
@AliasFor("value")
String[] origins() default {};
String[] originPatterns() default {};
String[] allowedHeaders() default {};
String[] exposedHeaders() default {};
RequestMethod[] methods() default {};
String allowCredentials() default "";
long maxAge() default -1L;
}
2.全局配置的方法
创建一个类实现WebMvcConfigurer接口,重写addCorsMappings方法
/**
* @author: 王泽
*
* /**表示本应用的所有方法都会去处理跨域请求
* allowedMethods表示允许通过的请求数
* allowedHeaders则表示允许的请求头。
* 经过这样的配置之后,就不必在每个方法上单独配置跨域了。
*/
public class WebCros implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8088")
.allowedMethods("*")
.allowedHeaders("*");
}
}
------------------------------------------------注意----------------------------------------------------------------
了解了整个CORS的工作过程之后,我们通过Ajax发送跨域请求,虽然用户体验提高了,但是也有潜在的威胁存在,常见的就是CSRF(Cross-site request forgery)跨站请求伪造。跨站请求伪造也被称为one-click attack 或者 session riding,通常缩写为CSRF或者XSRF,是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法,举个例子:
假如一家银行用以运行转账操作的URL地址如下:http://icbc.com/aa?bb=cc,那么,一个恶意攻击者可以在另一个网站上放置如下代码:<img src="http://icbc.com/aa?bb=cc">
,如果用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会遭受损失。
基于此,浏览器在实际操作中,会对请求进行分类,分为简单请求,预先请求,带凭证的请求等,预先请求会首先发送一个options探测请求,和浏览器进行协商是否接受请求。默认情况下跨域请求是不需要凭证的,但是服务端可以配置要求客户端提供凭证,这样就可以有效避免csrf攻击。
------------------------------------------------注意----------------------------------------------------------------
相信看到这里,小伙伴们也都明白springboot中如何实现跨域了吧,还望大家三连支持!