因為前一段時間做了一個系統持續操作期間自動重新整理token有效性的需求,然後就想著找一個空閒時間總結一下JWT,所以今天就簡單的記錄一下自己瞭解的內容。
JWT是什麼
- JWT全稱是JSON Web Token,是一個開放標準,它定義了一種緊湊的、自包含的結構,可用於在服務之間資訊傳遞和授權認證。
- 資訊傳遞:通過簽名,可以確保傳遞的資訊不被篡改且不是偽造的。
- 授權認證:通過JWT生成的token資訊進行驗籤,確保是自己服務簽發的token資訊。
- JWT的格式:
JWT由三部分組成,各部分之間使用[.]進行連線。各部分分別是:Header(頭資訊)、Payload(載荷)和Signature(簽名)。
其格式如下:
header.payload.signature
- 使用場景
前端頁面點選登入,後端驗證使用者名稱密碼通過後,使用JWT生成token資訊返回給前端,前端使用登入token請求各個介面。
JWT使用示例
首先引入JWT jar包如下:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
Java示例程式碼如下:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.*;
public class JWTDemo {
public static void main(String[] args) {
String issue = "ISSUE_CESHI";
// 簽名演算法
SignatureAlgorithm algorithm = SignatureAlgorithm.HS256;
// 簽名祕鑰
String secret = "CESHI_SECRET";
int timeout = 60 * 60 * 6;
long currentTime = System.currentTimeMillis();
Map<String,Object> map = new HashMap<>();
map.put("userId","10");
map.put("userName","張三");
String token = Jwts.builder()
.signWith(algorithm, secret)
.setClaims(map)
.setId(UUID.randomUUID().toString())
.setIssuedAt(new Date(currentTime))
.setIssuer(issue)
.setExpiration(new Date(currentTime + timeout * 1000))
.compact();
System.out.println(token);
Jws<Claims> parseResult3 = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
}
}
上面演示程式碼生成的token資訊如下:
eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJJU1NVRV9DRVNISSIsInVzZXJOYW1lIjoi5byg5LiJIiwiZXhwIjoxNjEwMzgzMzY0LCJ1c2VySWQiOiIxMCIsImlhdCI6MTYxMDM2MTc2NCwianRpIjoiY2QwNDM1ODctNGZmNS00OGY4LTk2YjUtNTA1ZTc4MzFkMGNjIn0.b_Fr8hpTC5nlwR4NikbEg1WpDMya2Gr5fCfNTV0iCOQ
然後將生成的token進行解析得到如下內容:
可以看到載荷裡面有我們設定的userId和userName資訊。
同時,JWT規定了7個官方的欄位,如下:
- iss (issuer):簽發人
- exp (expiration time):過期時間
- sub (subject):主題
- aud (audience):受眾
- nbf (Not Before):生效時間
- iat (Issued At):簽發時間
- jti (JWT ID):編號
需要特別注意的是,JWT的header和body部分都是用Base64進行編碼的,本身不具有加密屬性,所以在body中不能儲存敏感資訊。
系統持續操作自動重新整理token
JWT的一大優點就是token資訊儲存在客戶端,服務端不用儲存對應的授權資訊。因此,它的一大缺點就是一旦token頒發了就沒辦法進行撤銷,只有等待token自動失效。
如果想要實現token失效前撤銷,那麼只能藉助其他手段,比如使用redis快取,token驗證除了JWT本身的驗籤外,還需要判斷redis快取資訊,但是這樣做有違JWT的設計本意。
說說在專案中遇到的需求:就是在使用者持續間隔時間內作業系統,那麼系統內部應該自動重新整理token資訊,而不是在固定時間點強行要求重新登入。比如token頒發的有效期是5個小時,然後使用者一直操作到4小時59分59秒,然後在5小時0分1秒的時候提交一個表格,這時如果因為token失效直接跳轉到登入頁面,這樣的使用者體驗感是極為糟糕的。
所以為了解決上面的場景,在寫這個需求的時候,特地調研了一下各種方案,最後綜合了一下,決定採用redis實現。方案如下:
頒發一個足夠時長的token(比如15天),然後儲存在redis中,redis中設定短的有效期,比如6小時。從而實現在6小時內有效操作免登入。