1.jwt結構
jwt生成到客戶端(瀏覽器)的token包含"."分開的三個部分:
- header(Base64Url編碼過的)
- payload(Base64Url編碼過的)
- signature
形如:xxxxx.yyyyy.zzzzz
1.1 例子:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYW5keSIsImV4cCI6MTY1NTg5NzEwMCwiYWdlIjozMH0.32hfc-oBxGg2Lgk3QR48HCbadsbOfCUxexw9aiQ_FQk
拆為3部分:
- eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.(header)
- eyJuYW1lIjoiYW5keSIsImV4cCI6MTY1NTg5NzEwMCwiYWdlIjozMH0.(payload)
- 32hfc-oBxGg2Lgk3QR48HCbadsbOfCUxexw9aiQ_FQk(signature)
2.header+payload+signature介紹
2.1 header
上面的header部分:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
base64Url解碼後:
{
"typ": "JWT",
"alg": "HS256"
}
通常說明token的型別、生成token所使用的的演算法
The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.
2.2 Payload
上面的Payload部分:eyJuYW1lIjoiYW5keSIsImV4cCI6MTY1NTg5NzEwMCwiYWdlIjozMH0
base64Url解碼後:
{
"name": "andy",
"exp": 1655897100,
"age": 30
}
通常是要客戶端請求時帶貨的內容(比如使用者名稱,比如是否是管理員等,server端生成的時候可以定義內容,形式如map)
The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims.
2.3 Signature
上面的Signature部分:32hfc-oBxGg2Lgk3QR48HCbadsbOfCUxexw9aiQ_FQk
它是用來驗籤的, 驗證是否被客戶端修改過,它的生成邏輯如下:
就是使用header部分的base64Url、payload部分的base64Url部分、小圓點、以及你的私鑰密碼,使用指定的演算法生成的;因為有密碼, 所以是安全的,這也是密碼要保護好的原因。
計算邏輯如下:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
12345
)
3. java測試用例
/**
* JWT加密生成token, payload中儲存 name/age
*/
@Test
public void testJwtToken() {
// 加密祕鑰
final String SECRET = "12345";
Calendar c = Calendar.getInstance();
c.add(Calendar.HOUR, 2);
String token = JWT.create().withClaim("name", "andy")
.withClaim("age", 30)
.withExpiresAt(c.getTime())
.sign(Algorithm.HMAC256(SECRET));
System.out.println(token);
}
/**
* JWT解密生成token, 讀取payload中儲存的 name/age
*/
@Test
public void testJwtVerify() {
String jwtToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYW5keSIsImV4cCI6MTY1NTg4ODk3MiwiYWdlIjozMH0.LU4AQJkld03kDhatkiiArSJI4liGiANArTvoyswzk5I";
final String SECRET = "12345";
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
DecodedJWT decodedJWT = verifier.verify(jwtToken);
Claim name = decodedJWT.getClaim("name");
Claim age = decodedJWT.getClaim("age");
System.out.println(name);
System.out.println(age);
}