天天看點

JWT(JSON web token)

1.什麼是JWT

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA

—[摘自官網]

官網位址: https://jwt.io/introduction/

翻譯: jsonwebtoken(JWT)是一個開放标準(rfc7519),它定義了一種緊湊的、自包含的方式,用于在各方之間以JSON對象安全地傳輸資訊。此資訊可以驗證和信任,因為它是數字簽名的。jwt可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公鑰/私鑰對進行簽名

2.通俗解釋

JWT簡稱JSON Web Token,也就是通過JSON形式作為Web應用中的令牌,用于在各方之間安全地将資訊作為JSON對象傳輸。在資料傳輸過程中還可以完成資料加密、簽名等相關處理。

2.JWT能做什麼

這是使用JWT的最常見方案。一旦使用者登入,每個後續請求将包括JWT,進而允允許的路由,服務和資源。單點登入是當今廣泛使用JWT的一項功能,因為它的開銷很小并且可以在不同的域中輕松使用。

JSON Web Token是在各方之間安全地傳輸資訊的好方法。因為可以對JWT進行簽名(例如,使用公鑰/私鑰對),是以您可以確定發件人是他們所說的人。此外,由于簽名是使用标頭和有效負載計算的,是以您還可以驗證内容是否遭到篡改。

注意:jwt跟session不一樣,jwt存儲在用戶端,session存儲在伺服器端,伺服器斷電後session就沒了,而jwt因為存儲在用戶端,是以就不會被影響,隻要jwt不過期,就可以繼續使用。

3.為什麼是JWT

3.1 基于傳統的Session認證

我們知道,http協定本身是一種無狀态的協定,而這就意味着如果使用者向我們的應用提供了使用者名和密碼來進行使用者認證,那麼下一次請求時,使用者還要再一次進行使用者認證才行,因為根據http協定,我們并不能知道是哪個使用者發出的請求,是以為了讓我們的應用能識别是哪個使用者發出的請求,我們隻能在伺服器存儲一份使用者登入的資訊,這份登入資訊會在響應時傳遞給浏覽器,告訴其儲存為cookie,以便下次請求時發送給我們的應用,這樣我們的應用就能識别請求來自哪個使用者了,這就是傳統的基于session認證。

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-Y7ycQNpE-1621250075249)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210517123118644.png)]

1.每個使用者經過我們的應用認證之後,我們的應用都要在服務端做一次記錄,以友善使用者下次請求的鑒别,通常而言session都是儲存在記憶體中,而随着認證使用者的增多,服務端的開銷會明顯增大

2.使用者認證之後,服務端做認證記錄,如果認證的記錄被儲存在記憶體中的話,這意味着使用者下次請求還必須要請求在這台伺服器上,這樣才能拿到授權的資源,這樣在分布式的應用上,相應的限制了負載均衡器的能力。這也意味着限制了應用的擴充能力。

3.因為是基于cookie來進行使用者識别的, cookie如果被截獲,使用者就會很容易受到跨站請求僞造的攻擊。

4.在前後端分離系統中就更加痛苦:如下圖所示

也就是說前後端分離在應用解耦後增加了部署的複雜性。通常使用者一次請求就要轉發多次。如果用session 每次攜帶sessionid 到服務 器,伺服器還要查詢使用者資訊。同時如果使用者很多。這些資訊存儲在伺服器記憶體中,給伺服器增加負擔。還有就是CSRF(跨站僞造請求攻 擊)攻擊,session是基于cookie進行使用者識别的, cookie如果被截獲,使用者就會很容易受到跨站請求僞造的攻擊。還有就是 sessionid就是一個特征值,表達的資訊不夠豐富。不容易擴充。而且如果你後端應用是多節點部署。那麼就需要實作session共享機制。 不友善叢集應用。

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-rWMW6ei3-1621250075252)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210517123132784.png)]

3.2 基于JWT認證

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-RDhSDZFA-1621250075257)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210517123144086.png)]

首先,前端通過Web表單将自己的使用者名和密碼發送到後端的接口。這一過程一般是一個HTTP POST請求。建議的方式是通過SSL加密的傳輸(https協定),進而避免敏感資訊被嗅探。

後端核對使用者名和密碼成功後,将使用者的id等其他資訊作為JWT Payload(負載),将其與頭部分别進行Base64編碼拼接後簽名,形成一個JWT(Token)。形成的JWT就是一個形同lll.zzz.xxx的字元串。 token head.payload.singurater

後端将JWT字元串作為登入成功的傳回結果傳回給前端。前端可以将傳回的結果儲存在localStorage或sessionStorage上,登出時前端删除儲存的JWT即可。

前端在每次請求時将JWT放入HTTP Header中的Authorization位。(解決XSS和XSRF問題) HEADER

後端檢查是否存在,如存在驗證JWT的有效性。例如,檢查簽名是否正确;檢查Token是否過期;檢查Token的接收方是否是自己(可選)。

驗證通過後後端使用JWT中包含的使用者資訊進行其他邏輯操作,傳回相應結果。

簡潔(Compact): 可以通過URL,POST參數或者在HTTP header發送,因為資料量小,傳輸速度也很快

自包含(Self-contained):負載中包含了所有使用者所需要的資訊,避免了多次查詢資料庫

因為Token是以JSON加密的形式儲存在用戶端的,是以JWT是跨語言的,原則上任何web形式都支援。

不需要在服務端儲存會話資訊,特别适用于分布式微服務。

4.JWT的結構是什麼?

token string ====> header.payload.singnature token

1.标頭(Header)

2.有效載荷(Payload)

3.簽名(Signature)

是以,JWT通常如下所示:xxxxx.yyyyy.zzzzz Header.Payload.Signature

标頭通常由兩部分組成:令牌的類型(即JWT)和所使用的簽名算法,例如HMAC SHA256或RSA。它會使用 Base64 編碼組成 JWT 結構的第一部分。

注意:Base64是一種編碼,也就是說,它是可以被翻譯回原來的樣子來的。它并不是一種加密過程。

令牌的第二部分是有效負載,其中包含聲明。聲明是有關實體(通常是使用者)和其他資料的聲明。同樣的,它會使用 Base64 編碼組成 JWT 結構的第二部分

{

“sub”: “1234567890”,

“name”: “John Doe”,

“admin”: true

}

前面兩部分都是使用 Base64 進行編碼的,即前端可以解開知道裡面的資訊。Signature 需要使用編碼後的 header 和 payload 以及我們提供的一個密鑰,然後使用 header 中指定的簽名算法(HS256)進行簽名。簽名的作用是保證 JWT 沒有被篡改過

如:

HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload),secret);

最後一步簽名的過程,實際上是對頭部以及負載内容進行簽名,防止内容被竄改。如果有人對頭部以及負載的内容解碼之後進行修改,再進行編碼,最後加上之前的簽名組合形成新的JWT的話,那麼伺服器端會判斷出新的頭部和負載形成的簽名和JWT附帶上的簽名是不一樣的。如果要對新的頭部和負載進行簽名,在不知道伺服器加密時用的密鑰的話,得出來的簽名也是不一樣的。

在這裡大家一定會問一個問題:Base64是一種編碼,是可逆的,那麼我的資訊不就被暴露了嗎?

是的。是以,在JWT中,不應該在負載裡面加入任何敏感的資料。在上面的例子中,我們傳輸的是使用者的User ID。這個值實際上不是什麼敏 感内容,一般情況下被知道也是安全的。但是像密碼這樣的内容就不能被放在JWT中了。如果将使用者的密碼放在了JWT中,那麼懷有惡意的第 三方通過Base64解碼就能很快地知道你的密碼了。是以JWT适合用于向Web應用傳遞一些非敏感資訊。JWT還經常用于設計使用者認證和授權系 統,甚至實作Web應用的單點登入。

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-eUsd1ufU-1621250075259)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210517124718908.png)]

輸出是三個由點分隔的Base64-URL字元串,可以在HTML和HTTP環境中輕松傳遞這些字元串,與基于XML的标準(例如SAML)相比,它更緊湊。

簡潔(Compact)

可以通過URL, POST 參數或者在 HTTP header 發送,因為資料量小,傳輸速度快

自包含(Self-contained)

負載中包含了所有使用者所需要的資訊,避免了多次查詢資料庫

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-KqBOnvdb-1621250075260)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210517124748768.png)]

5.使用JWT

生成結果

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsicGhvbmUiLCIxNDMyMzIzNDEzNCJdLCJleHAiOjE1OTU3Mzk0NDIsInVzZXJuYW1lIjoi5byg5LiJIn0.aHmE3RNqvAjFr_dvyn_sD2VJ46P7EGiS5OBMO_TI5jg

SignatureVerificationException: 簽名不一緻異常

TokenExpiredException: 令牌過期異常

AlgorithmMismatchException: 算法不比對異常

InvalidClaimException: 失效的payload異常

6.封裝工具類

7.整合springboot

引入依賴

編寫配置

這裡采用最簡單的表結構驗證JWT使用

使用上述方式每次都要傳遞token資料,每個方法都需要驗證token代碼備援,不夠靈活? 如何優化

使用攔截器進行優化