Cookie、Session、Token,以及基於token的登陸身份校驗
cookie:
-
HTTP 是無狀態的協議(對於事務處理沒有記憶能力,每次客戶端和服務端會話完成時,服務端不會儲存任何會話資訊):每個請求都是完全獨立的,服務端無法確認當前訪問者的身份資訊,無法分辨上一次的請求傳送者和這一次的傳送者是不是同一個人。所以伺服器與瀏覽器為了進行會話跟蹤(知道是誰在訪問我),就必須主動的去維護一個狀態,這個狀態用於告知服務端前後兩個請求是否來自同一瀏覽器。而這個狀態需要通過 cookie 或者 session 去實現。
-
cookie 儲存在客戶端: cookie 是伺服器傳送到使用者瀏覽器並儲存在本地的一小塊資料,它會在瀏覽器下次向同一伺服器再發起請求時被攜帶併發送到伺服器上。
-
cookie 是不可跨域的: 每個 cookie 都會繫結單一的域名,無法在別的域名下獲取使用,一級域名和二級域名之間是允許共享使用的(靠的是 domain)。
session:
-
session 是另一種記錄伺服器和客戶端會話狀態的機制;
-
session 是基於 cookie 實現的,session 儲存在伺服器端,sessionId 會被儲存到客戶端的cookie 中;
-
session 認證流程:
-
使用者第一次請求伺服器的時候,伺服器根據使用者提交的相關資訊,建立對應的 Session
-
請求返回時將此 Session 的唯一標識資訊 SessionID 返回給瀏覽器
-
瀏覽器接收到伺服器返回的 SessionID 資訊後,會將此資訊存入到 Cookie 中,同時 Cookie 記錄此 SessionID 屬於哪個域名
-
當用戶第二次訪問伺服器的時候,請求會自動判斷此域名下是否存在 Cookie 資訊,如果存在自動將 Cookie 資訊也傳送給服務端,服務端會從 Cookie 中獲取 SessionID,再根據 SessionID 查詢對應的 Session 資訊,如果沒有找到說明使用者沒有登入或者登入失效,如果找到 Session 證明使用者已經登入可執行後面操作。
Cookie 和 Session 的區別
-
安全性: Session 比 Cookie 安全,Session 是儲存在伺服器端的,Cookie 是儲存在客戶端的。
-
存取值的型別不同:Cookie 只支援存字串資料,想要設定其他型別的資料,需要將其轉換成字串,Session 可以存任意資料型別。
-
有效期不同: Cookie 可設定為長時間保持,比如我們經常使用的預設登入功能,Session 一般失效時間較短,客戶端關閉(預設情況下)或者 Session 超時都會失效。
-
儲存大小不同: 單個 Cookie 儲存的資料不能超過 4K,Session 可儲存資料遠高於 Cookie,但是當訪問量過多,會佔用過多的伺服器資源。
token:
-
訪問資源介面(API)時所需要的資源憑證
-
簡單 token 的組成: uid(使用者唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,token 的前幾位以雜湊演算法壓縮成的一定長度的十六進位制字串)
-
特點:
-
服務端無狀態化、可擴充套件性好
-
支援移動端裝置
-
安全
-
支援跨程式呼叫
-
token 的身份驗證流程:
-
客戶端使用使用者名稱跟密碼請求登入;
-
服務端收到請求,去驗證使用者名稱與密碼;
-
驗證成功後,服務端會簽發一個 token 並把這個 token 傳送給客戶端;
-
客戶端收到 token 以後,會把它儲存起來,比如放在 cookie 裡或者 localStorage 裡;
-
客戶端每次向服務端請求資源的時候需要帶著服務端簽發的 token;
-
服務端收到請求,然後去驗證客戶端請求裡面帶著的 token ,如果驗證成功,就向客戶端返回請求的資料;
-
每一次請求都需要攜帶 token,需要把 token 放到 HTTP 的 Header 裡;
-
基於 token 的使用者認證是一種服務端無狀態的認證方式,服務端不用存放 token 資料。用解析 token 的計算時間換取 session 的儲存空間,從而減輕伺服器的壓力,減少頻繁的查詢資料庫;
-
token 完全由應用管理,所以它可以避開同源策略;
Refresh Token:
-
另外一種 token——refresh token
-
refresh token 是專用於重新整理 access token 的 token。如果沒有 refresh token,也可以重新整理 access token,但每次重新整理都要使用者輸入登入使用者名稱與密碼,會很麻煩。有了 refresh token,可以減少這個麻煩,客戶端直接用 refresh token 去更新 access token,無需使用者進行額外的操作。
-
Access Token 的有效期比較短,當 Acesss Token 由於過期而失效時,使用 Refresh Token 就可以獲取到新的 Token,如果 Refresh Token 也失效了,使用者就只能重新登入了。
-
Refresh Token 及過期時間是儲存在伺服器的資料庫中,只有在申請新的 Acesss Token 時才會驗證,不會對業務介面響應時間造成影響,也不需要向 Session 一樣一直保持在記憶體中以應對大量的請求。
Token 和 Session 的區別
-
Session 是一種記錄伺服器和客戶端會話狀態的機制,使服務端有狀態化,可以記錄會話資訊。而 Token 是令牌,訪問資源介面(API)時所需要的資源憑證。Token 使服務端無狀態化,不會儲存會話資訊。
-
Session 和 Token 並不矛盾,作為身份認證 Token 安全性比 Session 好,因為每一個請求都有簽名還能防止監聽以及重放攻擊,而 Session 就必須依賴鏈路層來保障通訊安全了。如果你需要實現有狀態的會話,仍然可以增加 Session 來在伺服器端儲存一些狀態。
-
所謂 Session 認證只是簡單的把 User 資訊儲存到 Session 裡,因為 SessionID 的不可預測性,暫且認為是安全的。而 Token ,如果指的是 OAuth Token 或類似的機制的話,提供的是 認證 和 授權 ,認證是針對使用者,授權是針對 App 。其目的是讓某 App 有權利訪問某使用者的資訊。這裡的 Token 是唯一的。不可以轉移到其它 App上,也不可以轉到其它使用者上。Session 只提供一種簡單的認證,即只要有此 SessionID ,即認為有此 User 的全部權利。是需要嚴格保密的,這個資料應該只儲存在站方,不應該共享給其它網站或者第三方 App。所以簡單來說:如果你的使用者資料可能需要和第三方共享,或者允許第三方呼叫 API 介面,用 Token 。如果永遠只是自己的網站,自己的 App,用什麼就無所謂了。
解決方案:
-
JSON Web Token(簡稱 JWT)是目前最流行的跨域認證解決方案。
-
是一種認證授權機制。
-
JWT 是為了在網路應用環境間傳遞宣告而執行的一種基於 JSON 的開放標準(RFC 7519)。JWT 的宣告一般被用來在身份提供者和服務提供者間傳遞被認證的使用者身份資訊,以便於從資源伺服器獲取資源。比如用在使用者登入上。
-
可以使用 HMAC 演算法或者是 RSA 的公/私祕鑰對 JWT 進行簽名。因為數字簽名的存在,這些傳遞的資訊是可信的。
-
JWT 認證流程:
-
使用者輸入使用者名稱/密碼登入,服務端認證成功後,會返回給客戶端一個 JWT
-
客戶端將 token 儲存到本地(通常使用 localstorage,也可以使用 cookie)
-
當用戶希望訪問一個受保護的路由或者資源的時候,需要請求頭的 Authorization 欄位中使用Bearer 模式新增 JWT,其內容看起來是下面這樣:
-
服務端的保護路由將會檢查請求頭 Authorization 中的 JWT 資訊,如果合法,則允許使用者的行為;
-
因為 JWT 是自包含的(內部包含了一些會話資訊),因此減少了需要查詢資料庫的需要;
-
因為 JWT 並不使用 Cookie 的,所以你可以使用任何域名提供你的 API 服務而不需要擔心跨域資源共享問題(CORS);
-
因為使用者的狀態不再儲存在服務端的記憶體中,所以這是一種無狀態的認證機制;
JWT 的使用方式
-
客戶端收到伺服器返回的 JWT,可以儲存在 Cookie 裡面,也可以儲存在 localStorage,更好的做法是放在 HTTP 請求頭資訊的 Authorization 欄位裡,使用 Bearer 模式新增 JWT。
Token 和 JWT 的區別
相同:
-
都是訪問資源的令牌
-
都可以記錄使用者的資訊
-
都是使服務端無狀態化
-
都是隻有驗證成功後,客戶端才能訪問服務端上受保護的資源
區別:
-
Token:服務端驗證客戶端傳送過來的 Token 時,還需要查詢資料庫獲取使用者資訊,然後驗證 Token 是否有效。
-
JWT:將 Token 和 Payload 加密後儲存於客戶端,服務端只需要使用金鑰解密進行校驗(校驗也是 JWT 自己實現的)即可,不需要查詢或者減少查詢資料庫,因為 JWT 自包含了使用者資訊和加密的資料。