HTTP Cookie是伺服器傳送得使用者瀏覽器並儲存在本地的一小塊資料,它會在瀏覽器下次向同一伺服器再發起請求時自動攜帶併傳送到伺服器上。換句話說,http請求攜帶cookie只發生在同源請求時。對於跨域請求,要攜帶cookie該怎麼解決這個問題呢?
技術背景:@vue/cli ^3 + axios + typescript + webpack ^4
HTTP請求分為簡單請求和預檢查請求,具體可以參考 跨域資源共享CORS詳解
HTTP請求頭中幾個重要的標誌:
- General中:
- Request URL:請求介面
- Remote Address:請求的伺服器地址
- Request Headers:
- Accept:接收資訊的格式,application/json, text/plain
- Origin:簡單請求會自動加上的請求源
- Response Headers
- Access-Control-Allow-Credentials:可選的布林值,表示是否允許傳送cookie。設為true,則伺服器允許cookie可以包含在請求中,否則不包括在cors請求中。
示例1(子域名不同):
為了實現單點登入,網站A:child.aaa.com要跳轉到主站B:www.aaa.com/login進行登入,並在登入後再次跳回child.aaa.com,此時在往網站A種下domain為aaa.com的cookie,之後再網站A傳送主站B:www.aaa.com介面的Http請求並需要攜帶該cookie獲取access_token以驗證使用者身份。
解決方案:
1. withCredentials: true
除了伺服器要同一可傳送cookie之外,客戶端發起http請求時也需要同步開啟withCredentials屬性。axios中具體寫法如下:
示例2(主域名不同):
為了實現單點登入,網站A:www.aaa.com要跳轉到主站B:www.bbb.com/login進行登入,並在登入後再次跳回www.aaa.com,此時在往網站A種下domain為home.com的cookie,之後再網站A傳送主站B:www.bbb.com介面的Http請求並需要攜帶該cookie獲取access_token以驗證使用者身份。
解決方案:
1. 首先withCredentials: true同上。
其次可以使用webpack的proxy代理
devServer: {
disableHostCheck: true, // 如果存在host、hosts的交叉請求,則需要忽略webpack中host檢查
proxy: {
'api/': {
target: 'www.bbb.com', // 最終請求的目標host
changeOrigin: true, // 預設false,儲存原host的header
secure: false // 預設true時,不接受https協議且證書無效的後端伺服器
}
}
}複製程式碼
這種方案由於不檢查請求頭協議,會存在CSRP攻擊,只適合開發階段使用。
2. 伺服器域名解析
可以在伺服器層,將aaa.com域名解析到bbb.com域名上,及在跳轉到主站B時,可以請求www.aaa.com/login後有伺服器重定向到www.bbb.com/login,介面請求時的原理同,此時調回子站A時cookie的domain是aaa.com,而介面請求時也會自主攜帶上cookie,不受瀏覽器跨域影響。