JWT

什么是JWT?

JSON Web Token(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為 JSON 對象在各方之間安全地傳輸信息。

說了一長串,不知道說的啥。。。。其實JWT就是用一種結(jié)構(gòu)化封裝的方式來生成token的技術(shù)。

JWT 這種結(jié)構(gòu)化體可以分為 HEADER(頭部)、PAYLOAD(數(shù)據(jù)體)和 SIGNATURE(簽名)三部分。經(jīng)過簽名之后的 JWT 的整體結(jié)構(gòu),是被句點符號分割的三段內(nèi)容,結(jié)構(gòu)為 header.payload.signature 。比如下面這個示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

我們拿著這個jwtToken去https://jwt.io/可以看到解密后的結(jié)果

HEADER:

{
  "alg": "HS256",
  "typ": "JWT"
}

PAYLOAD:

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}
  • HEADER:表示裝載令牌類型和算法等信息,是 JWT 的頭部。其中,typ 表示第二部分 PAYLOAD 是 JWT 類型,alg 表示使用 HS256 對稱簽名的算法。
  • PAYLOAD:數(shù)據(jù)體主要是我們的結(jié)構(gòu)化數(shù)據(jù),這組數(shù)據(jù)基本上都是我們自定義的信息。但是有幾個關(guān)鍵點大家需要注意一下:exp(令牌的過期時間戳)、iat(令牌頒發(fā)的時間戳)
  • SIGNATURE:表示對 JWT 信息的簽名。其實就是對HEADER與PAYLOAD進行一次加密處理,主要是驗證整個JWT內(nèi)容有沒有被篡改。

JWT的優(yōu)點

其實JWT最大的優(yōu)點就是為了設(shè)計無狀態(tài)的服務(wù)。

我們經(jīng)常可以聽到Http協(xié)議是無狀態(tài)的,而session是有狀態(tài)的,但是到底什么是有狀態(tài),什么是無狀態(tài)呢?這里我給大家簡單的科普一下:

所謂“狀態(tài)”,就是為了保留程序的一些數(shù)據(jù)或是上下文。

所以,大家可以知道,我們的軟件本身,肯定是有狀態(tài)的?。ǜ杏X是廢話,如果軟件不保留程序的數(shù)據(jù),或者沒有上下文,那這個軟件有個毛用?。?/p>

但是我們各種架構(gòu)設(shè)計,程序設(shè)計,都在強調(diào)設(shè)計無狀態(tài)的服務(wù),這怎么做呢?其實說白了,就是讓我們寫的程序,盡可能的“無狀態(tài)”,而把“有狀態(tài)”放到Redis,MySQL或者其他的分布式文件系統(tǒng)中。那么我們的服務(wù)就能可以隨意地增加和減少節(jié)點,同樣可以隨意地搬遷。而且,無狀態(tài)的服務(wù)可以大幅度降低代碼的復雜度以及 Bug 數(shù),因為沒有狀態(tài),所以也沒有明顯的“副作用”。對開發(fā)和運維來說,無狀態(tài)服務(wù)比有狀態(tài)的服務(wù)方便的多。

所以,我們用JWT作為Token,主要是通過“自編碼”的方式包含了身份驗證需要的信息,不再需要服務(wù)端進行額外的存儲,所以每次的請求都是無狀態(tài)會話。這就符合了我們盡可能遵循無狀態(tài)架構(gòu)設(shè)計的原則,也就是增強了系統(tǒng)的可用性和伸縮性。

JWT的缺點

其實JWT的缺點,就是它的優(yōu)點。

因為Token如果用“自編碼”的方式,不去存儲,那么就有一個很大的問題:覆水難收。

  • 用戶登出后,JWTToken依然有效
  • 用戶改密碼后,舊的JWTToken依然有效
  • 用戶被管理員踢出后,舊的JWTToken依然有效
  • JWTToken沒辦法“續(xù)約”,只能用申請新的Token

如何解決JWT的缺點

想要解決JWT的缺點,只能把部分信息存儲在客戶端,這是個無解的問題,想要徹底的做成“自編碼”而且又解決缺點,這是不可能的。

  • 以JWTToken為key,過期時間為value,在Redis等緩存中維護JWTToken的有效性

    其實這個方法也是可以的,但是不太友好。因為JWT的意義就是是把全部的信息放到JWT的PAYLOAD里面,如果用JWTToken為key,部分信息為value放到Redis中,其實是違背了JWT的設(shè)計初衷。而且JWTToken非常長,也不適合做緩存的key。

  • 以用戶ID為key,用戶密碼為value,或者為每個用戶生成一個秘鑰為value,放到Redis等緩存中

    JWT的SIGNATURE部分,我們可以設(shè)置一個“秘鑰”,哪怕HEADER與PAYLOAD相同,而秘鑰不同,最終生成的SIGNATURE也是不同的。所以,我們可以為每個用戶生成一個專屬的秘鑰,放在Redis等緩存中,當用戶改了密碼,或者被管理員踢出后,我們可以換掉用戶的秘鑰。那么下次用戶請求服務(wù)器時,我們對JWTToken進行校驗的時候,秘鑰改了,生成的SIGNATURE肯定不同,這樣就可以“收回”已經(jīng)無效的JWTToken了。

使用JWT需要注意的點

使用JWT作為Token,一定要注意里面的信息是否能給到第三方。如果不得不包含一些不能給到第三方的信息,那么JWTToken必須要加密。

因為JWT本身是包含了結(jié)構(gòu)化信息的,這里面有用戶的信息。如果不加密的話,不管是第三方、或者是用戶通過瀏覽器,都能夠知道JWT里面隱藏的信息。特別是用于OAuth2協(xié)議時,如果直接把JWT作為訪問令牌,那么第三方就能知道JWT里面的信息,而且這里面的信息可能第三方根本就沒有獲取到權(quán)限。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容