上篇文章提及到了JWT,以及為什么使用Token,這篇文章就圍繞JWT展開論述吧.
JWT 官方文檔:https://jwt.io/introduction/ 大致就是介紹了JWT是啥東西、運用場景 、怎么用..
基於cookie-session的認證
說到JWT,我覺得有必要來談談基於cookie-session的認證
我們都知道,http協議本身是一種無狀態的協議,也就是說用戶向我們的應用提供了用戶名和密碼進行身份認證,在下一次請求時,用戶還需要進行認證才行.因為根據http請求我們無法判斷是哪個用戶發送的請求,所以為了能識別是哪個用戶發出的請求,只能在服務端存儲一份用戶登錄的信息,這些信息在響應時傳遞給瀏覽器,並告訴它保存為cookie,以便下次請求是發送給后端,這樣后端就能識別請求來自哪個用戶.這就是傳統基於cookie-session的認證.
基於cookie-session身份驗證機制的過程
cookie-session認證
- 用戶輸入登錄信息
- 服務端驗證登錄信息是否正確,如果正確就在服務器端為這個用戶創建一個 Session,並把 Session 存入數據庫
- 服務器端會向客戶端返回帶有 sessionID 的 Cookie
- 客戶端接收到服務器端發來的請求之后,看見響應頭中的
Set-Cookie
字段,將 Cookie 保存起來 - 接下來的請求中都會帶上這個 Cookie,服務器將 sessionID 和 數據庫中的相匹配,如果有效則處理該請求
- 如果用戶登出,Session 會在客戶端和服務器端都被銷毀
cookie-session認證的缺陷
- 擴展性不好,當擁有多台服務器的情況下,如何共享 Session 會成為一個問題,也就是說,用戶第一個訪問的時候是服務器 A,而第二個請求被轉發給了服務器 B,那服務器 B 無法得知其狀態。(
- 安全性不好,攻擊者可以利用本地 Cookie 進行欺騙和 CSRF 攻擊。
- Session 保存在服務器端,如果短時間內有大量用戶,會影響服務器性能。
- 跨域問題,Cookie 屬於同源策略限制的內容之一。
基於jwt的鑒權機制
JWT認證
- 用戶使用用戶名密碼來請求服務器
- 服務器進行驗證用戶的信息
- 服務器通過驗證發送給用戶一個token
- 客戶端存儲token,並在每次請求時附送上這個token值
- 服務端驗證token值,並返回數據.這個token必須要在每次請求時傳遞給服務端,它應該保存在請求頭里, 另外,服務端要支持
CORS(跨來源資源共享)
策略,一般我們在服務端這么做就可以了Access-Control-Allow-Origin: *
。
JWT格式
JWT是由三段信息構成的,將這三段信息文本用.
鏈接一起就構成了JWT字符串。就像這樣:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
JWT官網地址:https://jwt.io/ 在首頁下部的Debugger部分可以對JWT字符串進行解析(Base64),如下.
Header
頭部含兩部分信息
- 類型聲明,這里是jwt
- 聲明加密的算法 常用的是HMAC SHA256
playload
載荷就是存放有效信息的地方。這個名字像是特指飛機上承載的貨品,這些有效信息包含三個部分
- 標准中注冊的聲明
- 公共的聲明
- 私有的聲明
標准中注冊的聲明 (建議但不強制使用) :
- iss: jwt簽發者
- sub: jwt所面向的用戶
- aud: 接收jwt的一方
- exp: jwt的過期時間,這個過期時間必須要大於簽發時間
- nbf: 定義在什么時間之前,該jwt都是不可用的.
- iat: jwt的簽發時間
- jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。
公共的聲明 :
公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.
私有的聲明 :
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味着該部分信息可以歸類為明文信息。
signature
jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:
- header (base64后的)
- payload (base64后的)
- secret
這個部分需要base64加密后的header和base64加密后的payload使用.
連接組成的字符串,然后通過header中聲明的加密方式進行加鹽secret
組合加密,然后就構成了jwt的第三部分。
注意:secret是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用來進行jwt的簽發和jwt的驗證,所以,它就是你服務端的私鑰,在任何場景都不應該流露出去。一旦客戶端得知這個secret, 那就意味着客戶端是可以自我簽發jwt了。