Django + Axios 跨域發(fā)送 cookie
為什么會(huì)變成這樣呢
3 人贊同了該文章
筆者的環(huán)境如下:
| 前端 | Vue | localhost:8080 |
| 后端 | Django | http://www.mydomain.com:80 |
可以看到抵知,前后端服務(wù)的域名和端口都不一樣按脚,因此在前后端進(jìn)行交互時(shí)必然會(huì)出現(xiàn)跨域的問題两踏,可以在后端使用 django-cors-headers 處理。
1. django-cors-headers
1.1 配置
pipenv install django-cors-headers # 使用 pipenv 安裝
在 Django settings.py 中配置如下
MIDDLEWARE = [
.........
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware', # 注意中間件安裝的位置
'django.middleware.common.CommonMiddleware',
.........
]
CORS_ORIGIN_ALLOW_ALL = True # 允許任意站點(diǎn)跨域請(qǐng)求
CORS_ALLOW_CREDENTIALS = True # 允許發(fā)送身份驗(yàn)證
理論上應(yīng)該在 INSTALLED_APPS 里注冊(cè) django-cors-headers 的没陡,但筆者沒有注冊(cè)也能正常使用。
1.2 原理
當(dāng)瀏覽器發(fā)送請(qǐng)求時(shí)索赏,Django會(huì)在響應(yīng)頭里添加屬性 access-control-allow-origin盼玄,它的值為客戶端的地址(筆者這里為 http://localhost:8080 ),這樣一來客戶端就會(huì)允許跨域請(qǐng)求了潜腻。
2. Axios 配置
在 Vue 中對(duì)服務(wù)器 API 進(jìn)行訪問埃儿,通常使用 Axios。在上述的配置下已經(jīng)能夠?qū)崿F(xiàn)跨域請(qǐng)求融涣,但 Axios 在發(fā)送請(qǐng)求時(shí)默認(rèn)是不發(fā)送 cookie 的童番,如果要通過 Axios 傳輸 cookie 等身份驗(yàn)證信息精钮,還要在 Axios 的中(筆者這里直接在入口文件 main.js 中配置)配置一句
axios.defaults.withCredentials = true;
3. 踩坑記錄
但是這時(shí)仍然不能正確進(jìn)行身份驗(yàn)證,在瀏覽器的返回信息里我們可以看到服務(wù)端已經(jīng)把 cookie 發(fā)送給了我們剃斧,但是瀏覽器卻拒絕接收轨香。
[圖片上傳失敗...(image-18d7fa-1636527192906)]
這是由于 set-cookie 的 SameSite 屬性造成的。從 MDN 文檔 中可以了解到:
SameSite 接受下面三個(gè)值:
Lax
Cookies允許與頂級(jí)導(dǎo)航一起發(fā)送幼东,并將與第三方網(wǎng)站發(fā)起的GET請(qǐng)求一起發(fā)送臂容。這是瀏覽器中的默認(rèn)值。(中英文有歧義根蟹,以如下英文為準(zhǔn))
Cookies are not sent on normal cross-site subrequests (for example to load images or frames into a third party site), but are sent when a user is*navigating to *the origin site (i.e. when following a link).Strict
Cookies只會(huì)在第一方上下文中發(fā)送策橘,不會(huì)與第三方網(wǎng)站發(fā)起的請(qǐng)求一起發(fā)送。None
Cookie將在所有上下文中發(fā)送娜亿,即允許跨域發(fā)送丽已。(注意:None 屬性還要配合 Secure 屬性一起使用)
Chrome 在 56 版本中增加了對(duì)于 SameSite 的支持,但那時(shí) SameSite 的默認(rèn)值被設(shè)置為 None买决,即允許跨域發(fā)送 cookie沛婴。
然而,在 Chrome 的 80 版本中將 SameSite 的默認(rèn)值改為了 Lax督赤,這樣一來嘁灯,服務(wù)器發(fā)送給我們的 cookie 就會(huì)被瀏覽器攔截。
3.2 解決方案
3.2.1 服務(wù)端方案
不難想到我們只需要在服務(wù)端做一些配置里,對(duì)于發(fā)送的 cookie 自動(dòng)添加 SameSite=None 和 Secure 屬性拌阴,所幸 django-cors-headers 已經(jīng)提供了方便的配置選項(xiàng)胰坟。
在 settings.py 中添加:
SESSION_COOKIE_SAMESITE = 'None'
CSRF_COOKIE_SAMESITE = 'None'
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
需要注意,此處的 None 需要設(shè)置為字符串類型羹奉,以免與 python 的關(guān)鍵字混淆
3.2.2 客戶端方案
考慮到在實(shí)際生產(chǎn)項(xiàng)目中我們的前端項(xiàng)目也是部署在相同的域名下的,因此這樣的跨域問題只會(huì)在開發(fā)過程中遇到约计,這樣我們可以直接關(guān)閉瀏覽器的這個(gè)新增的功能诀拭。
訪問 chrome://flags/#same-site-by-default-cookies 并將其設(shè)置為 Disabled。
經(jīng)驗(yàn)總結(jié)
留心關(guān)注報(bào)錯(cuò)提示信息煤蚌,善用搜索耕挨。