什么是Token(令牌)
Acesss 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,它是專用于刷新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一樣一直保持在內存中以應對大量的請求。
舉個例子簡單理解一下:
假設你去健身房鍛煉:
Access Token 就像健身房的「單次門禁卡」,有效期1小時(短期有效)。有了它,你能進入健身房使用各種器材。
Refresh Token 就像「補辦門禁卡的憑證」,有效期30天(長期有效)。當「單次門禁卡」過期后,你不用重新辦卡(不用重新輸入賬號密碼登錄),直接用這個憑證就能免費換一張新的「單次門禁卡」。你第一次去健身房(首次登錄),前臺對你的身份(驗證賬號密碼),給你一張「單次門禁卡」(Access Token)和一張「補辦憑證」(Refresh Token)。而1小時后「單次門禁卡」過期了(Access Token失效):你不用再去前臺重新登記(不用重新登錄),直接出示「補辦憑證」(Refresh Token),前臺就會給你一張新的「單次門禁卡」(新的Access Token)。30天后「補辦憑證」也過期了(Refresh Token失效):這時你必須重新去前臺登記(重新登錄),才能拿到新的「門禁卡」和「補辦憑證」。
為什么需要這樣設計?
- 如果只有Access Token且有效期很長:一旦被盜,別人可以長期冒用你的身份(不安全)。
- 如果只有短期的Access Token且沒有Refresh Token:過期后需要頻繁重新登錄(體驗差)。
- 有了Refresh Token:既保證了安全性(Access Token短期有效),又兼顧了便利性(不用頻繁登錄)。
Token和Cookie的區別
Cookie和Token雖然都能用于身份驗證,但兩者的設計邏輯和適用場景差異顯著。Cookie 是互聯網早期的產物,存在一些歷史遺留問題,而Token更能適應現代Web開發的復雜需求,因此兩者并非替代關系,而是根據場景互補使用。
Cookie是HTTP協議自帶的狀態傳遞工具,由瀏覽器自動存儲和發送,默認與特定域名綁定,存在跨域限制,且容易因自動發送的特性帶來CSRF等安全風險,存儲容量也被限制在4KB左右,更適合簡單的本地狀態存儲(如用戶偏好)。而Token是服務器生成的加密令牌,完全由開發者控制存儲位置(如localStorage、內存)和發送方式(如請求頭),不受跨域限制,也不會被瀏覽器自動攜帶,能避免Cookie的默認行為帶來的安全隱患,且可承載更多信息,更適合前后端分離、跨域API調用、移動端應用等場景。
Token和Session的區別
首先理解一下什么是Session:Session 是一種讓服務器能夠記錄客戶端(比如瀏覽器)會話狀態的機制。當用戶第一次訪問服務器時,服務器會為這個用戶創建一個獨特的 Session,里面可以存儲一些和該用戶相關的信息,比如登錄狀態、購物車內容等。同時,服務器會生成一個對應的 SessionID,并通過 Cookie 等方式發送給客戶端。之后,客戶端每次向服務器發送請求時,都會帶上這個 SessionID。服務器通過識別 SessionID,就能找到對應的 Session,從而知道這是哪個用戶的請求,以及該用戶之前的會話狀態,這樣就實現了服務端的“有狀態”交互。
舉個例子,你登錄一個購物網站后,添加商品到購物車,這些操作記錄會被保存在服務器為你創建的 Session 里。當你刷新頁面或跳轉到其他頁面時,瀏覽器會自動帶上 SessionID,服務器通過它找到你的 Session,所以購物車里的商品不會消失,這就是 Session 在起作用。不過,Session 是存儲在服務器端的,這意味著如果服務器集群部署,需要考慮 Session 共享的問題,否則用戶切換到集群中的其他服務器時,可能會因為找不到對應的 Session 而需要重新登錄。
因而,Session是服務器用來記錄和客戶端之間會話狀態的一種機制,它能讓服務器處于有狀態化,也就是能記住會話中的各種信息。而Token是一種令牌,是訪問資源接口(API)時必須有的資源憑證,它能讓服務器處于無狀態的狀態,不會去存儲會話方面的信息。
Session和Token并不是相互沖突的。作為身份認證的方式,Token的安全性比Session更好,因為每一個請求都會帶有簽名,能夠防止被監聽以及重放攻擊,而Session則必須依靠鏈路層來保證通訊的安全。如果需要實現有狀態的會話,還是可以增加Session在服務器端保存一些狀態信息。
所謂的Session認證,其實就是簡單地把用戶信息存儲到Session里,由于SessionID難以預測,所以暫時可以認為它是安全的。而Token,如果指的是OAuth Token或者類似的機制,它能提供認證和授權功能,認證是針對用戶的,授權是針對應用程序的。它的目的是讓某個應用程序有權限訪問某個用戶的信息。這里的Token是唯一的,不能轉移到其他應用程序上,也不能轉到其他用戶那里。Session只提供一種簡單的認證,只要有了這個SessionID,就會被認為擁有該用戶的全部權限。SessionID需要嚴格保密,只能保存在網站自己這邊,不應該共享給其他網站或者第三方應用程序。所以簡單來說,如果用戶數據可能需要和第三方共享,或者允許第三方調用API接口,那就用Token。如果始終只是自己的網站、自己的應用程序,用哪種都沒什么關系。