Cookie小記

下雨天DY發表於2018-11-12

> 需求描述:理解cookie



維持登入態的幾種方式:

傳統身份驗證的方法

HTTP 是一種沒有狀態的協議,也就是它並不知道是誰是訪問應用。這裡我們把使用者看成是客戶端,客戶端使用使用者名稱還有密碼通過了身份驗證,不過下回這個客戶端再傳送請求時候,還得再驗證一下。

解決的方法就是,當使用者請求登入的時候,如果沒有問題,我們在服務端生成一條記錄,這個記錄裡可以說明一下登入的使用者是誰,然後把這條記錄的 ID 號傳送給客戶端,客戶端收到以後把這個 ID 號儲存在 Cookie 裡,下次這個使用者再向服務端傳送請求的時候,可以帶著這個 Cookie ,這樣服務端會驗證一個這個 Cookie 裡的資訊,看看能不能在服務端這裡找到對應的記錄,如果可以,說明使用者已經通過了身份驗證,就把使用者請求的資料返回給客戶端。

上面說的就是 Session,我們需要在服務端儲存為登入的使用者生成的 Session ,這些 Session 可能會儲存在記憶體,磁碟,或者資料庫裡。我們可能需要在服務端定期的去清理過期的 Session 。

基於 Token 的身份驗證方法

使用基於 Token 的身份驗證方法,在服務端不需要儲存使用者的登入記錄。大概的流程是這樣的:

1、客戶端使用使用者名稱跟密碼請求登入
2、服務端收到請求,去驗證使用者名稱與密碼
3、驗證成功後,服務端會簽發一個 Token,再把這個 Token 傳送給客戶端
4、客戶端收到 Token 以後可以把它儲存起來,比如放在 Cookie 裡或者 Local Storage 裡
5、客戶端每次向服務端請求資源的時候需要帶著服務端簽發的 Token
6、服務端收到請求,然後去驗證客戶端請求裡面帶著的 Token,如果驗證成功,就向客戶端返回請求的資料

Cookie


Cookie種類


1、臨時Cookie(會話Cookie)
2、永久Cookie

cookie分為兩種,一種是硬碟上的,另一種是記憶體上的,一個網站通常有一個.txt檔案來存Cookies,一個Cookie物件最終轉換為txt檔案中的一條記錄。儲存在瀏覽器執行緒分配的記憶體中的Cookie物件,在關閉這個瀏覽器視窗後,就銷燬了。導致種類不同是過期時間的設定與否決定的,如果設定了過期時間,那麼就會在過期時間未到前一直生效,請求會被攜帶,除非服務端設定了max-age強制使其失效;而沒有設定過期時間,cookie的生命週期只存在於瀏覽器會話期間,關閉視窗,cookie即消失。

Cookie被攜帶的條件

同一域名下,存在cookie,瀏覽器會預設自動傳送Cookie給對應的伺服器。
普通的ajax(json)請求和jsop跨域請求是預設攜帶cookie的,而cors跨域請求和fetch請求預設是不攜帶cookie的。因此,當我們的請求需要攜帶cookie時,我們就要對cors跨域請求和fetch請求這兩中請求方式進行特殊配置處理。
通常我們使用的axios庫,也是對XMLHttpRequest這個物件的封裝,和ajax請求無異,因為加入了promise,解決了回撥的問題。
而fetch請求如果想攜帶cookie,需要設定header裡面的引數,加上credientials: ‘include’;
CORS的方式想要攜帶cookie,需要設定如下設定

// aixos為例const service = axios.create({baseURL: process.env.BASE_API, // node環境的不同,對應不同的baseURLtimeout: 30000, // 請求的超時時間withCredentials: true // 允許攜帶cookie})複製程式碼


設定Cookie的方式

1、後端設定set-cookie,這種情況下,前端什麼也不需要做。相當於伺服器端給瀏覽器傳送指令,瀏覽器自動注入cookie;,每次請求都攜帶cookie資訊;
2、前端收到後端返回的資訊,設定cookie;

function setDomainCookie(name, value, expiresDays = 60, host) {let date = new Date();date.setTime(date.getTime() + expiresDays * 24 * 3600 * 1000);const expires = `expires=${date.toGMTString()};`;host? '': (host = window.location.hostname.split('.').slice(-2).join('.'));const domain = `domain=${host};`;window.document.cookie = `${name}=${value};${expires}${domain}path=/`;}複製程式碼


分析 && 總結
1、cookie資訊自動被請求攜帶,不限於請求後端資料的請求,即使是重新整理頁面,圖片,css,js,也都會攜帶本地的cookie資訊,這無疑相當於浪費了請求頭的資源;
2、cookie是不允許跨域傳輸的,所以在本地localhost傳送的請求是不會被攜帶到請求頭裡的,這樣就會有問題,如果很多請求都需要驗證許可權,而開發環境又無法攜帶cookie資訊,就會帶來聯調上的困難;
3、cookie中能夠儲存的資料有限,不同的瀏覽器限制大小不一樣。

綜上,在實現自動登入時,前端收到服務端返回的token,可以存到localstorage裡,然後塞入請求頭中,所有對於資料的請求都會攜帶此頭部欄位,雖然localstorage沒有過期這一概念,我們可以自己手動設定,每次傳送請求前都判斷一遍是否過期,如下:

// 存入if (cacheParams.cacheTime < 0) cacheParams.cacheTime = 3600000;var result = { data: response.data, expiration: new Date().getTime() + cacheParams.cacheTime };localStorage.setItem(cacheParams.cacheName, JSON.stringify(result));// 取出判斷const data = JSON.parse(data);if (parseInt(data.expiration) - new Date().getTime() <= 3000) {// 說明已過期,做相應處理}複製程式碼

設定請求頭:

// 以axios例項為例netApi.interceptors.request.use((request) => {removePending(request); // 在一個ajax傳送前執行一下取消操作config.cancelToken = new APICancelToken((c) => {// 這裡的ajax標識我是用請求地址&請求方式拼接的字串,當然你可以選擇其他的一些方式pending.push({ u: `${request.url}&${request.method}`, f: c });});if (readLocalStorage('X-Token')) {request.headers.token = readLocalStorage('X-Token'); // 攜帶token}return request;}, error => Promise.reject(error));複製程式碼

題外記,如果存有登入資訊的cookie檔案,被複制到另一臺裝置的指定目錄下,去訪問這個cookie對應的網站,是不是也能正常訪問呢?
我的理解是可以的,或者換一種方式,我的裝置上的cookie資訊被劫持了,然後被用來登入我使用的網站了,是不是意味著這個人在行駛著我的權力,理論上是,可是現在的安全防範策略那麼多,能夠存到cookie裡的資訊未必是最重要的明文資訊,所以即使被劫持了也影響不大。


歡迎指正!


參考文章:
1、[React16新的生命週期函式getDerivedStateFromProps的使用,你也許並不需要派生狀態【譯】](https://blog.csdn.net/nnxxyy1111/article/details/80832525)
2、[HTTP--Request Headers及Cookies](https://www.cnblogs.com/wxinyu/p/8005621.html)
3、[狀態保持中的Cookie與Session](https://blog.csdn.net/sundacheng1989/article/details/8194466)
4、[CORS簡介](https://www.cnblogs.com/loveis715/p/4592246.html)
5、[axios的cookie跨域以及相關配置
](https://segmentfault.com/a/1190000011811117?utm_source=tag-newest)


相關文章