一.什么是JWT?
JSONWebToken,通过数字签名的方式,以JSON对象为载体,在不同的服务终端之间安全的传输信息。
二.JWT有什么用?
JWT 最常见的场景就是授权认证,一旦用户登录,后续每个请求都将包含JWT,系统在每次处理用户请求的之前,都要先进行安全校验,通过之后再进行处理。
三.JWT的组成
JWT由3部分 Header.Payload.Signature组成,用.拼接
eyJhbGcioiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6I1RvbSIsInJvbGUioiJhZG1pbiIsInN1YiI6ImFkbwluLXR1c3QiLCJ1eHAiojE2MjMyMjM2NzUsImp0aSI6ImQ2MTJjzjcxLWI5ZmUtNGMwNy04MzQwLTViOWViZmMyNjExNyJ9.F0S9Y7rYNdc2AOidnSPrgg2XTYePU0yGZ598h2gtabE
1. Header(头部)
javascript
{
"typ": "JWT",
"alg": "HS256"
}
- typ: 令牌类型,固定为 JWT
- alg: 签名算法,这里是 HS256(HMAC-SHA256)
Base64Url 编码后:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
2. Payload(载荷)
javascript
{
"username": "Tom",
"role": "admin",
"sub": "admin-tust",
"exp": 1623223675,
"jti": "d612c771-b9fe-4c07-8340-5b9ebfc26117"
}
常见字段说明:
- sub: 主题(subject)
- exp: 过期时间(Unix 时间戳)
- jti: 唯一标识符
Base64Url 编码后:eyJ1c2VybmFtZSI6I1RvbSIsInJvbGUioiJhZG1pbiIs...
3. Signature(签名)
javascript
计算方式:
signature = HMAC-SHA256(
base64urlEncode(header) + "." + base64urlEncode(payload),
secret_key
)
即:用 Header 和 Payload 的 Base64Url 编码拼接,再用密钥通过 HS256 算法签名。
四.使用
与Java项目结合
引入依赖
我是jdk1.8所以不需要加入其它依赖
XML
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
如果是 JDK 9 及以上,需要额外引入 JAXB 依赖(因为 JAXB 从 JDK 11 起被移除)
XML
<!-- jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- JAXB(JDK 11+ 必须) -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
编写代码
加密
java
private Long time = 1000 * 60 * 60 * 24; // 24小时
private String signature = "admin";
@org.junit.Test
public void jwt() {
String jwtToken = Jwts.builder()
// header
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
// payload
.claim("username", "tom")
.claim("role", "admin")
.setSubject("admin-test")
.setExpiration(new Date(System.currentTimeMillis() + time))
.setId(UUID.randomUUID().toString())
// signature
.signWith(SignatureAlgorithm.HS256, signature)
.compact();
System.out.println(jwtToken);
}
解密
java
@org.junit.Test
public void parse() {
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."; // 待解析的token
// 创建解析器,设置签名密钥(必须和生成时一致,否则校验失败)
JwtParser jwtParser = Jwts.parser();
// 解析并验证签名,得到 Jws 对象(包含 Header + Payload)
Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
// 获取 Payload 部分(载荷数据)
Claims claims = claimsJws.getBody();
// 读取自定义字段
System.out.println(claims.get("username")); // 输出:tom
System.out.println(claims.get("role")); // 输出:admin
// 读取标准字段
System.out.println(claims.getId()); // 输出:唯一ID
System.out.println(claims.getSubject()); // 输出:admin-test
System.out.println(claims.getExpiration()); // 输出:过期时间
}