前言:本文解決的問題
- 基於session 認證的不足
- 基於 token 認證的過程
- session VS tooken
1.傳統基於Cookie 認證的過程
長期以來,基於Session的認證(Session based authentication)一直處於主流地位。由於http協議是無狀態的,借助cookie,客戶端登陸成功后,服務端就能識別其后續請求,而不需要每次都登陸。它是*有狀態的(statefull),也就是服務端和客戶端都需要保存生成的session**,也就是說在服務端需要在數據庫中追蹤session是否alive,客戶端要把session寫入cookie中。基本過程如下:
- 客戶端登陸,一般輸入用戶名和密碼
- 服務端如果驗證通過,就會生成session,並把它存入數據庫中
- 客戶端在瀏覽器上會產生cookie,並把session寫入
- 客戶端后續有新的請求,都會在請求后攜帶sessIon,發給服務端
- 如果客戶端登陸出去(log out),該生成的session就會在客戶端和服務端都被銷毀
如下圖:
基於Session 認證的不足
正如圖片所示,服務端需要保存每個用戶的session,這對於很多訪問用戶的情景來說,服務端的負擔很重,需要大量的的資源來存儲session;另一方面不能很好解決跨域資源共享問題Cross-Origin Resource Sharing (CORS)。最重要的是cookie的使用引入了很多不安全因素,招致了很多專門針對cookie的攻擊。
2. 基於token的認證
近年來,基於token的認證開始成為主流,不管是單個網頁,還是web app,還是*Internet of Things *。該認證方式是無狀態的(stateless),客戶端登陸成功后,服務端會生成一個token並把它返還給客戶端,由於是無狀態的,服務端不再保存該Token。
問題來了,當客戶端再發送請求時,服務端如何判斷它曾經已經登陸了?類似Sesssion based authentication,客戶端每次發送請求時也會攜帶Token。由於這里的Token是服務端用自己的密鑰簽名的,當它受到客戶但的Token時,只需要再用自己的密鑰去驗證,就可以判斷這個Token是不是剛自己簽發的。這里面的核心就是用簽名和驗證,從而減輕了服務端的負擔,無需再存儲session,尤其是對於大型的分布式應用,減負很多。以下是具體的過程:
- 客戶端用自己的機密信息登陸,如用戶名和密碼
- 服務端驗證,驗證通過,生成Token返還給客戶端(一般用哈希算法,再加個隨機數)。
- 客戶端把Token寫入local storage(本地內存),后續請求都攜帶該Token
- 服務端收到請求時驗證Token,如果驗證通過,則允許用戶訪問相應資源
問題
由於這里Token是后續用來登陸的唯一認證手段,如果用戶關閉了網頁,被其它別有用心的應用竊取到Token,拿它再來登陸就危險了。因此這里需要服務端給Tooken設置過期時間(expired time),不能太長,太長不安全;太短用戶體驗差。另外,當用戶登出時,服務端要把當前Token設為黑名單(back list),防止被冒用。
3. 基於token的優點
- 無狀態,stateless
服務端無需保存生成的Token,它需要做的就是簽發Token,並驗證它。由於Token中是含有需要驗證的所有信息(簽名算法、用戶信息、簽名),這就讓服務端負載減輕了很多
- 交叉域和交叉域共享Cross-domain / CORS
Cookie和CORS在不同的域效果不好。而使用基於Token可以使API應用到不同的服務和域中。
- 可以在JWT中存儲數據 Store Data in the JWT
我們知道,現通用的Token based Authentication 就是JOSN Web Token(jwt)。JWT包含頭部(header),載荷(claim set), 和簽名(signature)。可以在載荷中存放預定義的元數據,只要是JOSON格式就可以了。
- 不需要CSRF(cross-site-request-forgery)防護
由於不需要依賴Cookie,自然不用擔心Cookie被截獲,用戶信息被偽造登陸問題。