一、什么是同源策略?
1、同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。
2、所謂同源是指"協議+域名+端口"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。
3、同源策略限制以下幾種行為:
(1)Cookie、LocalStorage 和 IndexDB 無法讀取
(2)DOM 和 Js對象無法獲得
(3)AJAX 請求不能發送
瀏覽器采用同源策略,禁止頁面加載或執行與自身來源不同的域的任何腳本。換句話說瀏覽器禁止的是來自不同源的"document"或腳本,對當前"document"讀取或設置某些屬性。
情景:
比如一個惡意網站的頁面通過iframe嵌入了銀行的登錄頁面(二者不同源),如果沒有同源限制,惡意網頁上的javascript腳本就可以在用戶登錄銀行的時候獲取用戶名和密碼。
瀏覽器中有哪些不受同源限制呢?
<script>、<img>、<iframe>、<link>這些包含 src 屬性的標簽可以加載跨域資源。但瀏覽器限制了JavaScript的權限使其不能讀、寫加載的內容。
常見的解決方案分為三種,Nginx代理(前端實現),JSONP(前端實現),后台設置(后端實現)。
1.Nginx代理(前端實現):
案例說明:前端項目部署在8081端口,后端8081端口。
nginx監聽8081端口,將前端從nginx監聽的端口8081請求過來的請求,代理轉發到8080端口(8080為后端接口)
1、JSONP
前端實現:
$.ajax({ url: 'http://www.domain2.com:8080/login', type: 'get', dataType: 'jsonp', // 請求方式為jsonp jsonpCallback: "onBack", // 自定義回調函數名 data: {} });
后端實現(SpringBoot)
@ControllerAdvice(basePackages = "com.zkn.learnspringboot.web.controller") public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{ public JsonpAdvice() { super("callback","jsonp"); } }
(1)前端發起請求時候,會加一個參數表示回調的函數 比如 callback=callback124 (callback 參數名也是可以自定義的,和后端協商好就行)
后端返回的數據 callback124({“uid”:1})
(2)參考:前端常見跨域解決方案(全) https://segmentfault.com/a/1190000011145364
(3)JSONP的缺點
JSONP只支持 GET 請求。
(4)原理
JSONP 是通過動態添加<script>標簽來調用服務器的腳本(<script>含有src屬性,src屬性沒有跨域限制);而 Ajax 是通過 XHR(XmlHttpRequest) 對象。
2、跨域技術-CORS (CrossOrigin Resources Sharing,跨源資源共享)
CORS是什么?
CORS,是 HTML5 的一項特性,它定義了一種瀏覽器和服務器交互的方式來確定是否允許跨域請求。
相對於 JSONP 這種解決方案來說,使用CORS,不需要要求服務器以指定格式返回數據(包裝成JS腳本的格式:callback_func({ data }););CORS,只需要在服務器端做一些通用設置。
前端實現:
$.ajax({ type: "post", url: 'http://192.168.45.152:8081/conference/user/bind', async: false, // 使用同步方式 // 1 需要使用JSON.stringify 否則格式為 a=2&b=3&now=14... // 2 需要強制類型轉換,否則格式為 {"a":"2","b":"3"} data: JSON.stringify({ a: 1, b: '2', now: new Date().getTime() // 注意不要在此行增加逗號 }), headers: { 'Authentication':'xxxxxx' }, contentType: "text/plain", dataType: "json", success: function(data) { console.log(data) } // 注意不要在此行增加逗號 });
后端實現(SpringBoot):
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { //設置允許跨域的路徑 registry.addMapping("/**") //設置允許跨域請求的域名 .allowedOrigins("*") //是否允許證書 不再默認開啟 .allowCredentials(true) //設置允許的方法 .allowedMethods("GET", "POST") //跨域允許時間 .maxAge(3600); } }
CORS與JSONP的使用目的相同,但是比JSONP更強大。
JSONP只支持GET請求,CORS支持所有類型的HTTP請求。JSONP的優勢在於支持老式瀏覽器,以及可以向不支持CORS的網站請求數據。
四、跨域會話保持
對於前端來說,seesion字段是存在cookie中的。在跨域過程中,Cookie是默認不發送的。就算后端返回set-Cookie字段,前端也不會保存Cookie,更不會在下一次訪問的時候發送到后端了。
因此只要前端可以把cookie發送到后端,后端就可以根據cookie拿到seeion字段進行會話驗證。
進過重新對CORS的學習,只要通過3步,就可以讓會話保持。
1、在ajax中設置,withCredentials: true。
默認情況下,跨源請求不提供憑據(cookie、HTTP認證及客戶端SSL證明等)。通過將withCredentials屬性設置為true,可以指定某個請求應該發送憑據。
$.ajax({ url: a_cross_domain_url, xhrFields: { withCredentials: true } });
第二第三步,就是上面的服務端CORS的跨域技術
服務端的 Access-Control-Allow-Credentials: true,代表服務器接受Cookie和HTTP認證信息。
參考資料:
(1)前后端分離-跨域會話如何保持?
https://www.jianshu.com/p/26f877d2b315?tdsourcetag=s_pcqq_aiomsg
(2)Session與Token認證機制 前后端分離下如何登錄
https://www.cnblogs.com/eret9616/p/9661314.html?tdsourcetag=s_pcqq_aiomsg
(3)理解Cookie和Session機制
https://www.cnblogs.com/andy-zhou/p/5360107.html
轉: https://blog.csdn.net/kevinxxw/article/details/90547184