jwt應該如何使用呢?
下面來寫一個最簡單的jwt的使用demo
1. 引入依賴包:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
2. 加密解密方法
public static void main(String[] args) {
// 過期時間
final Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, 1000);
// 以abc為密鑰進行hmac256方法加密,保存 a,b兩個屬性
final String token = JWT.create().withHeader(new HashMap<>())
.withClaim("a", "ccc")
.withClaim("b", JSONObject.toJSON(Arrays.asList("a", "b", "c")).toString())
.withExpiresAt(instance.getTime())
.sign(Algorithm.HMAC256("abc"));
System.out.println("token = " + token);
// 解密
JWTVerifier build = JWT.require(Algorithm.HMAC256("abc")).build();
final DecodedJWT verify = build.verify(token);
// 取出a
final Claim a = verify.getClaim("a");
System.out.println("a = " + a);
System.out.println("a.asString() = " + a.asString());
// 取出b
final Claim b = verify.getClaim("b");
System.out.println("b = " + b);
System.out.println("b.asArray(List.class) = " + b.asString());
// 取出過期時間
final Date expiresAt = verify.getExpiresAt();
System.out.println("expiresAt = " + expiresAt.toLocaleString());
}
在生產環境中,一般jwt會保存用戶的名字和角色權限等信息。可以將token 寫到cookie里,每次前端訪問后台時,可以在攔截器或者過濾器取到token, 然后解密,先判斷是否過期,過期就拋異常阻止其訪問。然后取出信息保存到threadLocal里,方便以后調用這些信息,當后台訪問完成后,從thredLocal刪除此用戶信息。
3. 如何使用
登陸返回JWT, 客戶端瀏覽器拿到這個 JWT 字符串后,存儲到 cookie 或者 瀏覽器的 LocalStorage 中。再次發送請求,比如請求用戶設置頁面的時候,在 HTTP 請求頭中加入 JWT 字符串,或者直接放到請求主體中。
登錄過后給前端進行返回JWT並設置了過期時間30分鍾,后端接收請求的時候獲取請求頭出來進行jwt解析判斷過期時間是否小於10分鍾,如果小於10分鍾就生成新的 jwt 在responseHearde進行返回即可,前端每次都檢查responseHearde是否有jwt, 如果有,則替換localStorage 中的jwt .
jwt 結構解析
JWT由3部分組成:標頭(Header)、有效載荷(Payload)和簽名(Signature)
Header
JWT頭是一個描述JWT元數據的JSON對象,alg屬性表示簽名使用的算法,默認為HMAC SHA256(寫為HS256);typ屬性表示令牌的類型,JWT令牌統一寫為JWT。最后,使用Base64 URL算法將上述JSON對象轉換為字符串保存
{
"alg": "HS256",
"typ": "JWT"
}
Payload
是JWT的主體內容部分,也是一個JSON對象,包含需要傳遞的數據。 JWT指定七個默認字段供選擇
iss:發行人
exp:到期時間
sub:主題
aud:用戶
nbf:在此之前不可用
iat:發布時間
jti:JWT ID用於標識該JWT
這些預定義的字段並不要求強制使用。除以上默認字段外,我們還可以自定義私有字段,一般會把包含用戶信息的數據放到payload中
{ "sub": "1234567890", "name": "Helen", "admin": true ,roles:["admin","comsumer"]}
Signature
簽名哈希部分是對上面兩部分數據簽名,需要使用base64編碼后的header和payload數據,通過指定的算法生成哈希,以確保數據不會被篡改。首先,需要指定一個密鑰(secret)。該密碼僅僅為保存在服務器中,並且不能向用戶公開。
在計算出簽名哈希后,JWT頭,有效載荷和簽名哈希的三個部分組合成一個字符串,每個部分用.分隔,就構成整個JWT對象

注意JWT每部分的作用,在服務端接收到客戶端發送過來的JWT token之后:
header和payload可以直接利用base64解碼出原文,從header中獲取哈希簽名的算法,從payload中獲取有效數據
signature由於使用了不可逆的加密算法,無法解碼出原文,它的作用是校驗token有沒有被篡改。服務端獲取header中的加密算法之后,利用該算法加上secretKey對header、payload進行加密,比對加密后的數據和客戶端發送過來的是否一致。注意secretKey只能保存在服務端,而且對於不同的加密算法其含義有所不同,一般對於MD5類型的摘要加密算法,secretKey實際上代表的是鹽值
JWT 有效期內可以
JWT 有個問題,那就是一旦頒發一個 JWT 令牌,服務端就沒辦法廢棄掉它,除非等到它自身過期。有很多應用默認只允許最新登錄的一個客戶端正常使用,不允許多端登錄,JWT 就沒辦法做到,因為頒發了新令牌,但是老的令牌在過期前仍然可用。這種情況下,就需要服務端增加相應的邏輯。
