jwt和session的區別和優缺點

背景知識:Authentication和Authorization的區別:

Authentication:用戶認證,指的是驗證用戶的身份,例如你但願以小A的身份登陸,那麼應用程序須要經過用戶名和密碼確認你真的是小A。redis

Authorization:受權,指的是確認你的身份以後提供給你權限,例如用戶小A能夠修改數據,而用戶小B只能閱讀數據。算法

因爲http協議是無狀態的,每一次請求都無狀態。當一個用戶經過用戶名和密碼登陸了以後,他的下一個請求不會攜帶任何狀態,應用程序沒法知道他的身份,那就必須從新認證。所以咱們但願用戶登陸成功以後的每一次http請求,都可以保存他的登陸狀態。數據庫

目前主流的用戶認證方法有基於token和基於session兩種方式。json

基於session的用戶認證

基於session的認證流程以下: 後端

img

  1. 用戶輸入其登陸信息
  2. 服務器驗證信息是否正確,並建立一個session,而後將其存儲在數據庫中
  3. 服務器爲用戶生成一個sessionId,將具備sesssionId的Cookie將放置在用戶瀏覽器中
  4. 在後續請求中,會根據數據庫驗證sessionID,若是有效,則接受請求
  5. 一旦用戶註銷應用程序,會話將在客戶端和服務器端都被銷燬

基於token(令牌)的用戶認證

最經常使用的是JSON Web Token(jwt): 瀏覽器

img

  1. 用戶輸入其登陸信息
  2. 服務器驗證信息是否正確,並返回已簽名的token
  3. token儲在客戶端,例如存在local storage或cookie中
  4. 以後的HTTP請求都將token添加到請求頭裏
  5. 服務器解碼JWT,而且若是令牌有效,則接受請求
  6. 一旦用戶註銷,令牌將在客戶端被銷燬,不須要與服務器進行交互一個關鍵是,令牌是無狀態的。後端服務器不須要保存令牌或當前session的記錄。

jwt的組成

jwt的認證原理:

一個jwt實際上就是一個字符串,它由三部分組成,頭部、載荷與簽名,這三個部分都是json格式。安全

頭部(Header)

頭部用於描述關於該JWT的最基本的信息,例如其類型以及簽名所用的算法等。服務器

{
  "typ": "JWT",
  "alg": "HS256"
}
複製代碼

在這裏,咱們說明了這是一個JWT,而且咱們所用的簽名算法是HS256算法。cookie

載荷(Payload)

載荷能夠用來放一些不敏感的信息。session

{
    "iss": "John Wu JWT",
    "iat": 1441593502,
    "exp": 1441594722,
    "aud": "www.example.com",
    "sub": "jrocket@example.com",
    "from_user": "B",
    "target_user": "A"
}
複製代碼

這裏面的前五個字段都是由JWT的標準所定義的。

  • iss: 該JWT的簽發者
  • sub: 該JWT所面向的用戶
  • aud: 接收該JWT的一方
  • exp(expires): 何時過時,這裏是一個Unix時間戳
  • iat(issued at): 在何時簽發的 把頭部和載荷分別進行Base64編碼以後獲得兩個字符串,而後再將這兩個編碼後的字符串用英文句號.鏈接在一塊兒(頭部在前),造成新的字符串:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0
複製代碼

簽名(signature)

最後,咱們將上面拼接完的字符串用HS256算法進行加密。在加密的時候,咱們還須要提供一個密鑰(secret)。加密後的內容也是一個字符串,最後這個字符串就是簽名,把這個簽名拼接在剛纔的字符串後面就能獲得完整的jwt。header部分和payload部分若是被篡改,因爲篡改者不知道密鑰是什麼,也沒法生成新的signature部分,服務端也就沒法經過,在jwt中,消息體是透明的,使用簽名能夠保證消息不被篡改。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM
複製代碼

區別和優缺點:

基於session和基於jwt的方式的主要區別就是用戶的狀態保存的位置,session是保存在服務端的,而jwt是保存在客戶端的。

jwt的優勢:

  1. 可擴展性好 應用程序分佈式部署的狀況下,session須要作多機數據共享,一般能夠存在數據庫或者redis裏面。而jwt不須要。
  2. 無狀態 jwt不在服務端存儲任何狀態。RESTful API的原則之一是無狀態,發出請求時,總會返回帶有參數的響應,不會產生附加影響。用戶的認證狀態引入這種附加影響,這破壞了這一原則。另外jwt的載荷中能夠存儲一些經常使用信息,用於交換信息,有效地使用 JWT,能夠下降服務器查詢數據庫的次數。

jwt的缺點:

  1. 安全性

因爲jwt的payload是使用base64編碼的,並無加密,所以jwt中不能存儲敏感數據。而session的信息是存在服務端的,相對來講更安全。

  1. 性能

jwt太長。因爲是無狀態使用JWT,全部的數據都被放到JWT裏,若是還要進行一些數據交換,那載荷會更大,通過編碼以後致使jwt很是長,cookie的限制大小通常是4k,cookie極可能放不下,因此jwt通常放在local storage裏面。而且用戶在系統中的每一次http請求都會把jwt攜帶在Header裏面,http請求的Header可能比Body還要大。而sessionId只是很短的一個字符串,所以使用jwt的http請求比使用session的開銷大得多。

  1. 一次性

無狀態是jwt的特色,但也致使了這個問題,jwt是一次性的。想修改裏面的內容,就必須簽發一個新的jwt。

(1)沒法廢棄 經過上面jwt的驗證機制能夠看出來,一旦簽發一個jwt,在到期以前就會始終有效,沒法中途廢棄。例如你在payload中存儲了一些信息,當信息須要更新時,則從新簽發一個jwt,可是因爲舊的jwt還沒過時,拿着這個舊的jwt依舊能夠登陸,那登陸後服務端從jwt中拿到的信息就是過期的。爲了解決這個問題,咱們就須要在服務端部署額外的邏輯,例如設置一個黑名單,一旦簽發了新的jwt,那麼舊的就加入黑名單(好比存到redis裏面),避免被再次使用。

(2)續簽 若是你使用jwt作會話管理,傳統的cookie續簽方案通常都是框架自帶的,session有效期30分鐘,30分鐘內若是有訪問,有效期被刷新至30分鐘。同樣的道理,要改變jwt的有效時間,就要簽發新的jwt。最簡單的一種方式是每次請求刷新jwt,即每一個http請求都返回一個新的jwt。這個方法不只暴力不優雅,並且每次請求都要作jwt的加密解密,會帶來性能問題。另外一種方法是在redis中單獨爲每一個jwt設置過時時間,每次訪問時刷新jwt的過時時間。

能夠看出想要破解jwt一次性的特性,就須要在服務端存儲jwt的狀態。可是引入 redis 以後,就把無狀態的jwt硬生生變成了有狀態了,違背了jwt的初衷。並且這個方案和session都差很少了。

總結

適合使用jwt的場景:

  • 有效期短
  • 只但願被使用一次

好比,用戶註冊後發一封郵件讓其激活帳戶,一般郵件中須要有一個連接,這個連接須要具有如下的特性:可以標識用戶,該連接具備時效性(一般只容許幾小時以內激活),不能被篡改以激活其餘可能的帳戶,一次性的。這種場景就適合使用jwt。

而因爲jwt具備一次性的特性。單點登陸和會話管理很是不適合用jwt,若是在服務端部署額外的邏輯存儲jwt的狀態,那還不如使用session。基於session有不少成熟的框架能夠開箱即用,可是用jwt還要本身實現邏輯。

連接:http://www.javashuo.com/article/p-zlayjiuh-mg.html

相關文章
相關標籤/搜索