1. 程式人生 > 實用技巧 >很多人都把jwt用錯了,千萬不要再犯這種錯誤

很多人都把jwt用錯了,千萬不要再犯這種錯誤

jwt介紹

jwt(JSON Web Token)本身是一個行業標準,用於端與端之間安全的將資訊作為json物件傳輸,核心思想是通過雜湊演算法(不可逆演算法)做簽名,從而驗證訊息是否被篡改過,和https簽名演算法是一樣的原理。

jwt官網介紹
jwt常用的雜湊演算法(sha演算法)與java實現

jwt做登入的由來

最一開始做登入,就是將登入後生成唯一token返回,同時將token和使用者對應起來存在資料庫,以後這個使用者操作的時候,就得帶著這個token,伺服器通過查詢資料庫,就知道這個token是對應的哪個使用者了。
像這種將使用者和token儲存在服務端的做法,其實已經可以解決所有問題了。

但隨著有人發現,使用jwt,可以不用儲存token,也可以達到驗證使用者的效果,那當然最好了,和資料庫互動當然是越少越好。
所以,使用jwt做的登入,就是登入後用jwt簽名生成特殊格式的token(token中至少包括使用者資訊和簽名信息)返回,不儲存資料庫,以後使用者操作的時候,帶上token,伺服器就拿著使用者資訊對簽名信息做演算法驗證,驗證通過說明token有效。

jwt核心token解析

接下來詳細說下這個用jwt簽名生成特殊格式的token:
這個token是一個字串,用.隔開,總共有三部分:Header.Payload.Signature

Header是頭資訊json格式通過base64編碼生成的字串,頭資訊一般存放著生成token的演算法,因為生成token的雜湊演算法有多種,所以需要在頭資訊中指出是哪個。

Payload是荷載資訊,其實就是存放一些系統自定義資訊,比如使用者標識,也是json格式通過base64編碼生成的字串。

Signature是簽名字串,是將Header.Payload字串+系統內定的金鑰secret,通過雜湊演算法生成的簽名信息。

借一張官網原圖:
在這裡插入圖片描述

jwt為什麼可以是無狀態的

分析一下為什麼jwt可以做到不用服務端儲存,就能驗證是不是已登入的使用者:
首先,Payload中,都會存放使用者資訊,比如使用者名稱,所以驗證的時候,伺服器端就知道是哪個使用者了。
那麼,萬一這個token資訊是被人篡改過呢,由於token的第三部分Signature是通過雜湊演算法得到的,也就是不可逆的,Signature=雜湊演算法(Header.Payload,系統內定的金鑰secret),所以只要Header.Payload被改過,伺服器端重新算出的Signature就和傳過來的Signature對不上了。

同時,伺服器端這個系統內定的金鑰secret是最重要的,只要這個不被洩露出去,這個token就絕對安全。這個其實也是提醒各位設計系統的小夥伴,如果你的系統是一個很重要的系統,那就別用jwt了,因為萬一你這個系統內定金鑰洩露,任何人就都有可能模擬使用者登入了。

網上的錯誤使用案例

看完這些,咱們再說說,網上的一些誤人子弟的教程:

比如,當你搜索jwt redis的時候,就會發現有很多人都在寫,由於jwt是無狀態的,所以伺服器端如果伺服器端不儲存token,就沒法做token過期的功能,比如使用者登入的token,過30分鐘不用就自動失效的功能。

於是,有個騷操作就被想出來了,甚至是很多人都這樣做了,那就是選擇在伺服器端再用redis快取使用者,並加上過期時間,那麼每次token驗證的時候,再驗證一下redis中的使用者key是否過期就好了。

講真的,這麼做的這些人就不懂jwt。因為我們用jwt的本意,就是為了不和資料庫互動,那你再加個redis,那用jwt還有啥優勢,那還不如直接生成唯一token,記錄在redis中,不是更好麼。

其實要做token失效,也有不用redis的做法,這個做法也是我想出來的,那就是在Header.Payload.Signature的Payload中,加入過期時間,每次驗證的時候都驗證一下當前時間是否大於過期時間就好了,但這種做法,至今沒在網上看到過。