1. 概述
JSON Web Token (JWT) 是一種常用的 REST API 安全機制。儘管 JWT 可以被 Spring Security OAuth 等框架解析,但我們可能希望在自己的代碼中處理 JWT。
在本教程中,我們將 解碼並驗證 JWT 的完整性。
2. JWT 結構
首先,讓我們瞭解 JWT 的結構:
- 頭部 (Header)
- 有效負載 (Payload) (通常被稱為 body)
- 簽名 (Signature)
簽名是可選的。一個有效的 JWT 可以只包含頭部和有效負載部分。但是,我們使用簽名部分來驗證頭部和有效負載的內容,以確保安全授權 。
部分以 base64url 編碼的字符串表示,並用點 (‘.’) 分隔。 按照設計,任何人都可以解碼 JWT 並讀取頭部和有效負載部分的內容。但是,我們需要訪問用於創建簽名的密鑰,才能驗證令牌的完整性。
通常,JWT 包含用户的“聲明”(claims)。這些聲明代表有關用户的元數據,API 可以使用這些元數據來授予權限或跟蹤提供令牌的用户。解碼令牌允許應用程序使用數據,而驗證允許應用程序信任 JWT 由可信來源生成。
讓我們看看如何在 Java 中解碼和驗證令牌。
3. 解碼 JWT
我們可以使用內置的 Java 函數來解碼令牌。
首先,讓我們將令牌分解成其部分:
String[] chunks = token.split("\\.");我們應該注意的是,傳遞給 String.split 的正則表達式使用了轉義的 ‘.’ 字符,以避免 ‘.’ 表示“任意字符”。
我們的 chunks 數組現在應該包含兩個或三個元素,對應於 JWT 的部分。
接下來,讓我們使用 base64url 解碼器解碼 header 和 payload 部分:
Base64.Decoder decoder = Base64.getUrlDecoder();
String header = new String(decoder.decode(chunks[0]));
String payload = new String(decoder.decode(chunks[1]));讓我們用 JWT 運行這段代碼(您可以在線解碼它以進行比較:https://jwt.io/#encoded-jwt)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkJhZWxkdW5nIFVzZXIiLCJpYXQiOjE1MTYyMzkwMjJ9.qH7Zj_m3kY69kxhaQXTa-ivIpytKXXjZc1ZSmapZnGE輸出將提供解碼後的頭部以及任何有效負載:
{"alg":"HS256","typ":"JWT"}{"sub":"1234567890","name":"Baeldung User","iat":1516239022}如果僅定義了 JWT 的標頭和有效負載部分,我們已經完成了併成功解碼了信息。
4. 驗證 JWT
接下來,我們可以通過使用簽名部分,驗證標頭和有效負載的完整性,以確保它們未被篡改。
4.1. 依賴項
為了進行驗證,我們可以將 jjwt 添加到我們的 pom.xml 中:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>我們應該注意的是,我們需要從版本 0.7.0 及其後續版本中獲取該庫。
4.2. 配置簽名算法和密鑰規範
為了驗證有效負載和標頭,我們需要使用原始簽名令牌時所使用的簽名算法以及密鑰:
SignatureAlgorithm sa = SignatureAlgorithm.HS256;
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), sa.getJcaName());在本示例中,我們已經硬編碼了簽名算法為 HS256。但是,我們可以解碼頭部 JSON 並讀取 alg 字段以獲取該值。
我們也應該注意到,變量 secretKey 是密鑰的字符串表示形式。我們可能通過應用程序的配置或由發出 JWT 的服務提供的 REST API 提供給它。
4.3. 執行驗證
現在我們已經獲得了簽名算法和密鑰,就可以開始執行驗證。
JwtParser jwtParser = Jwts.parser()
.verifyWith(secretKeySpec)
.build();
try {
jwtParser.parse(token);
} catch (Exception e) {
throw new Exception("Could not verify JWT token integrity!", e);
}我們來分解一下這個過程。
首先,我們創建一個使用所選算法和密鑰的 JwtParser。然後,我們使用 JwtParser 解析令牌。解析方法內部的實現會生成一個新的簽名並將其與提供的簽名進行比較。如果它們相等,則表明我們已驗證了頭部和有效負載的完整性。如果拋出任何異常,則意味着令牌無效(可能是格式錯誤、過期等)。
5. 結論
在本文中,我們探討了 JWT 的結構以及如何將其解碼為 JSON。
然後,我們使用一個庫來驗證令牌的完整性,利用其簽名、算法和密鑰。