chrome禁止三方cookie,网站登录不了怎么办
背景
新版chrome(80+)瀏覽器默認(rèn)屏蔽所有三方cookie已經(jīng)不是什么新聞了,具體原因這里不去深究,有大量相關(guān)文章介紹,由于目前許多網(wǎng)站都依賴三方cookie,因此該特性的推出還是造成了一些的影響,比如收集用戶信息的廣告商,而且主流的瀏覽器都跟進(jìn)chrome的策略,已經(jīng)成為了既定事實(shí),本篇文章主要聚焦于各種解決方案,大家可以針對自身情況采用不同的解決辦法。
限制說明
SameSite
cookie新增的屬性,取值包括:Lax(默認(rèn)),None,Strict
1.None?:將關(guān)閉SameSite屬性,前提是必須同時(shí)設(shè)置Secure屬性(Cookie 只能通過 HTTPS 協(xié)議發(fā)送),否則無效;
2.Strict?:嚴(yán)格模式,完全禁止第三方 Cookie,跨站點(diǎn)時(shí),任何情況下都不會(huì)發(fā)送 Cookie。換言之,只有當(dāng)前網(wǎng)頁的 URL 與請求目標(biāo)一致,才會(huì)帶上 Cookie;
3.Lax?:規(guī)則稍稍放寬,大多數(shù)情況也是不發(fā)送第三方 Cookie,但是導(dǎo)航到目標(biāo)網(wǎng)址的 Get 請求除外,具體可參考文末鏈接【1】;
總數(shù)所述,要解決我們的問題,要么都是同一域名,一勞永逸,要么采用https協(xié)議+SameSite=none,或者不用新版瀏覽器,除此之外,好像也沒有什么辦法了(如果有,請告訴我-_-)。
解決方案
1.chrome設(shè)置
這種方式比較簡單,手動(dòng)禁用瀏覽器的限制功能,可參考文末鏈接【2】:
2.使用低版本瀏覽器
這也是一種解決方式,但是不推薦;
3.https協(xié)議 + SameSite=None
這主要依賴運(yùn)維和后端處理了,但是這種方式在以后新版瀏覽器中可能會(huì)失效,因?yàn)檫^兩年瀏覽器將全面禁止三方cookie,到時(shí)候怎么設(shè)置都不起作用了;
4.代理服務(wù)
如果上面的方式都不滿足,可以考慮采用node作為請求-應(yīng)答的中間層,大體設(shè)計(jì)如圖:
前端項(xiàng)目和代理服務(wù)位于同一個(gè)服務(wù)器,協(xié)議和域名一致,只是端口不同而已,為什么要這么設(shè)計(jì)呢,便于cookie共享,?因?yàn)閏ookie是不區(qū)分協(xié)議和端口的,因此只要域名(或者ip)一致,那么在同一臺(tái)電腦上就可以讀取同域名下的cookie?。
還需要說明的一點(diǎn)就是跨域問題是瀏覽器的安全策略,對于代理服務(wù)和后端服務(wù)來說就沒有跨域一說了,而是進(jìn)程間的通信。
接下來我們實(shí)現(xiàn)一個(gè)比較簡單的三方cookie請求示例,其中各個(gè)服務(wù)的訪問地址如下(都是本地模擬,因此代理和后端服務(wù)的ip一致,而真實(shí)情況往往不同):
前端項(xiàng)目:?http://127.0.0.1:8000
node代理服務(wù):?http://127.0.0.1:8001
后端服務(wù):?http://127.0.0.1:8002
示例演示與流程
1.登錄驗(yàn)證
首先需要輸入正確的用戶信息獲取cookie,這里我們使用iframe+postmessage的方式實(shí)現(xiàn)跨域登錄請求,流程分為:
1.訪問http://127.0.0.1:8000,打開登陸界面,輸入用戶名和密碼
2.點(diǎn)擊登錄,登錄頁面通過postMessage將登錄信息發(fā)送給http://127.0.0.1:8001頁面,這個(gè)頁面獲取登錄信息后調(diào)用http://127.0.0.1:8001/login登錄接口
3.請求到node代理服務(wù)后端,然后發(fā)起對真正的服務(wù)后端請求,然后將后端服務(wù)的響應(yīng)返回給前端頁面
4.如果校驗(yàn)成功,響應(yīng)頭會(huì)攜帶Set-Cookie信息,在http://127.0.0.1:8001的域下寫入cookie,同時(shí)http://127.0.01:8000也會(huì)寫入同樣的cookie
2.cookie讀取
成功登錄之后,在http://127.0.0.1:8000和http://127.0.0.1:8001都保存有cookie,實(shí)現(xiàn)了共享,可以通過document.cookie獲取,如果服務(wù)端返回的cookie是httponly,這時(shí)可以在代理服務(wù)層將這個(gè)屬性去掉就可以讀取了。
3.查詢數(shù)據(jù)
發(fā)起信息查詢時(shí),需要攜帶登陸成功后設(shè)置的cookie,這里就不通過iframe+postMessage的方式了,直接調(diào)用8001的接口服務(wù),但是要注意一點(diǎn)的就是,?由于是跨域的腳本請求,因此是不會(huì)自動(dòng)攜帶cookie信息的(即便是在客戶端可以實(shí)現(xiàn)cookie共享)?,如果設(shè)置withcredentials相關(guān)屬性,則還是三方cookie跨域的問題,是不容許攜帶cookie的,因此我們需要手動(dòng)設(shè)置一個(gè)請求頭?_cookie(cookie前面加了個(gè)下劃線前綴)?,將cookie帶上去。
8001上的代理獲取到查詢請求時(shí),解析請求頭的_cookie參數(shù),然后重新設(shè)置請求頭的cookie參數(shù),再發(fā)送給真正的后端服務(wù)接口,這時(shí)候就可以實(shí)現(xiàn)cookie的校驗(yàn)了。
4.代碼實(shí)現(xiàn)
文件結(jié)構(gòu)圖
1.) 前端項(xiàng)目
2.) node代理服務(wù)
---`http://127.0.0.1:8001`---<script type="text/javascript">var appHost = "http://127.0.0.1:8000";function login(event) { // 調(diào)用代理服務(wù)登錄接口$.ajax({type : "POST",contentType: "application/json",data: JSON.stringify(event.data.payload),url : "/login",success : function(result) {event.source.postMessage(result, event.origin); // 調(diào)用成功,發(fā)送返回?cái)?shù)據(jù)給用戶頁面},error : function(e){event.source.postMessage(e, event.origin);}});}function receiveMessage(event) {if (event.origin !== appHost) {return;}if (event.data.url === '/login') {login(event);}}window.addEventListener("message", receiveMessage, false);</script>---代理服務(wù)腳本---......const CORS_HEADER = {'Access-Control-Allow-Origin': 'http://127.0.0.1:8000','Access-Control-Allow-Headers': 'Content-Type, _cookie','Access-Control-Allow-Credentials': 'true',};......function sendProxyRequest(req, res) {const { method, headers, url } = req;const chunks = [];if(Object.hasOwnProperty.call(headers, '_cookie')) { // 包含自定義_cookie請求頭,重新設(shè)置cookieheaders.cookie = headers._cookie;}req.on('data', (chunk) => {chunks.push(chunk);});req.on('end', () => {const request = http.request({ // 發(fā)送請求到后端服務(wù)host: '127.0.0.1',port: 8002,path:url,method,headers,}, (response) => {res.writeHead(response.statusCode, {...CORS_HEADER,...response.headers,});response.pipe(res);});request.end(Buffer.concat(chunks).toString());});}3.) 后端服務(wù)
......const { method, headers, url } = req;const _method = method.toLowerCase();if (url === '/login' && _method === 'post') { // 登錄驗(yàn)證const chunks = [];req.on('data', (chunk) => {chunks.push(chunk);});req.on('end', () => {const result = {code: -1,message: 'login fail',};const resHeaders = {'Content-Type': 'text/json',};const { name, pass } = JSON.parse(Buffer.concat(chunks).toString());if (name === '123' && pass === 'abc') { // 這里只校驗(yàn)123&abc這種情況result.code = 0;result.message = 'login success';resHeaders['Set-Cookie'] = `sid=abc; Max-Age=${getCookieExpires()};`; // 設(shè)置cookie}res.writeHead(200, resHeaders);res.end(JSON.stringify(result));});......return;}if (url === '/fetchUser' && _method === 'post') { // 用戶信息查詢if (req.headers.cookie === 'sid=abc') { // 校驗(yàn)cookieres.writeHead(200, {'Content-Type': 'text/json',});......} else {res.writeHead(401);res.end();}return;}總結(jié)
第四種方法可以不修改后端服務(wù),微調(diào)前端項(xiàng)目即可,因此對于現(xiàn)有項(xiàng)目改造成本較低,但是需要維護(hù)一個(gè)node服務(wù)代理,上面的示例演示了http協(xié)議,對于https站點(diǎn),只需要稍微修改下node代理服務(wù)即可(https模塊+根證書),最后再說一點(diǎn),在前后端分離模式下,開發(fā)過程中遇到這樣的問題,可以設(shè)置webapck的服務(wù)代理,具體可參考資料【4】,本文就講到這里,大家如果有更好的解決方案,歡迎留言交流。
參考資料
【1】http://www.ruanyifeng.com/blog/2019/09/cookie-samesite.html
【2】https://www.cnblogs.com/Summer6/p/11671204.html
【3】https://juejin.im/post/6844904128557105166
【4】https://www.yuque.com/mdtvv0/myv5bw/es2oeo
總結(jié)
以上是生活随笔為你收集整理的chrome禁止三方cookie,网站登录不了怎么办的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Git 图形化操作之合并提交记录
- 下一篇: 初识ABP vNext(11):聚合根、