介绍
JJWT(Java JWT)是 Java 生态里最主流、企业用得最多的 JWT 工具库,专门用来在后端(SpringBoot/SpringCloud 等)生成、签名、解析、验证 JWT 令牌,做登录鉴权、接口授权、微服务间身份传递。
一、JJWT 是什么
- 全称:Java JWT(Java JSON Web Token)
- 定位:纯 Java 实现的 JWT 开源库,完全遵循 RFC 7519(JWT)、RFC 7515(JWS)、RFC 7516(JWE) 等规范
- 适用:SpringBoot 2/3、微服务、单体应用、Android 等 JVM 环境
- 特点:API 简洁、链式调用、安全校验强、异常清晰
二、核心能力(你代码里用到的就是这些)
1. 生成 JWT(签发)
- 存放用户信息:claims(自定义数据)、subject(用户名)
- 标准字段:签发时间 issuedAt、过期时间 expiration
- 签名防篡改:signWith(密钥)(HMAC/RSA/ECDSA)
- 最终生成:compact() → 一段
xxx.yyy.zzz字符串
2. 解析与验证(你代码里的 parser)
- 验签:verifyWith(密钥) → 确保没被篡改
- 自动校验:过期、签名错误、格式非法 直接抛异常
- 取数据:parseSignedClaims(token).getPayload() → 拿到用户信息
3. 支持的算法(企业常用)
- 对称签名(简单安全):HS256 / HS384 / HS512(你现在用的就是这类)
- 非对称(更高安全):RS256 / ES256 / PS256(适合微服务/公钥分发)
三、版本与依赖
1. 主流版本(企业最稳)
- 0.9.x:老版,API 不同(已淘汰)
- 0.11.x:过渡版
- 0.12.x:当前企业主流、最推荐
2. 0.12.x 关键变化(和你代码直接相关)
- 新 API:
- 签名:
signWith(SecretKey)(不再传算法) - 解析:
verifyWith(SecretKey).build().parseSignedClaims()
- 签名:
- 强制安全:
- HMAC 密钥 必须 ≥32 字节(你代码里
secret要够长) - 自动拒绝弱算法、弱密钥
- HMAC 密钥 必须 ≥32 字节(你代码里
版本选择
一、企业存量项目(最多、最稳):0.11.5
- 现状:80% 以上老项目、Spring Boot 2.x 主流在用
- 特点:
- 稳定、无坑、文档/案例最多
- 兼容 JDK 8 ~ 17、Spring Boot 2.x
- 依赖拆分:
jjwt-api+jjwt-impl+jjwt-jackson - API:
parserBuilder()、signWith(key, alg)风格
- 为什么流行:
- 0.11.x 是 长期稳定分支,修复了大量安全漏洞(含 CVE 防护)
- 很多公司技术栈锁在 Spring Boot 2.7.x / JDK 11,配套就是 0.11.5
二、新项目 / Spring Boot 3 标配:0.12.3 ~ 0.12.5
- 你现在用的 0.12.5 就是这个阵营的最新稳定版
- 特点:
- 原生支持 Spring Boot 3 / Jakarta EE(jakarta.servlet)
- 简化依赖:单 jar
jjwt包含全部(api+impl+jackson) - API 更简洁:
Jwts.builder().signWith(key)、parser().verifyWith(key).build() - 更强安全校验(拒绝伪签名、不合规 JWT)
- 适用:
- Spring Boot 3.0+、JDK 17+ 新项目必选
- 你现在的版本 完全正确、企业主流、可直接上生产
三、过时版本(不要再用)
- 0.9.1 及更早:
- 非常老、API 不兼容、不支持 Spring Boot 3
- 方法:
setSigningKey(String)、parser().setSigningKey()已废弃
springboot3 实现 JWT
提醒
SpringBoot3 必须用 JJWT 0.12.3+ 版本!
旧版 JJWT(0.9.1)不支持 SpringBoot3(Jakarta),会直接报错!
一、pom.xml 依赖(直接复制)
<!-- JJWT 最新版(SpringBoot3 专用) -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.12.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.12.3</version>
<scope>runtime</scope>
</dependency>
二、application.yml 配置
# JWT 配置
jwt:
secret: yourSecretKeyyourSecretKeyyourSecretKeyyourSecretKey # 密钥要足够长
expire: 86400000 # 过期时间 1天
三、JWT 工具类
JwtUtil.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;
/**
* JWT工具类
* 用于生成Token、解析Token、校验Token、从Token中获取用户信息
* 适配 jjwt 0.12.3+ 版本 & SpringBoot3
*/
@Component
public class JwtUtil {
/**
* JWT 密钥
* 从配置文件读取,长度必须 >=32 位,用于签名加密
*/
@Value("${jwt.secret}")
private String secret;
/**
* Token 过期时间
* 从配置文件读取,单位:毫秒
*/
@Value("${jwt.expire}")
private Long expire;
/**
* 获取加密密钥
* 将配置的字符串密钥转为 JJWT 需要的 SecretKey 对象
*/
private SecretKey getSecretKey() {
return Keys.hmacShaKeyFor(secret.getBytes());
}
/**
* 生成 JWT Token
* @param claims 自定义载荷(存放用户ID、角色等信息)
* @param username 用户名(作为Token的唯一标识)
* @return 生成好的 Token 字符串
*/
public String generateToken(Map<String, Object> claims, String username) {
return Jwts.builder()
.claims(claims) // 设置自定义载荷(存放额外信息)
.subject(username) // 设置主题(一般放用户名/账号)
.issuedAt(new Date()) // 设置签发时间(当前时间)
.expiration(new Date(System.currentTimeMillis() + expire)) // 设置过期时间
.signWith(getSecretKey())// 使用密钥签名(保证Token不被篡改)
.compact(); // 生成最终的 Token 字符串
}
/**
* 解析 Token,获取载荷(Claims)
* 会自动校验:签名是否正确 + 是否过期
* @param token 前端传入的 Token
* @return Token 中的载荷数据
*/
public Claims extractClaims(String token) {
return Jwts.parser()
.verifyWith(getSecretKey()) // 设置密钥,用于校验签名
.build() // 构建解析器
.parseSignedClaims(token) // 解析并校验 Token
.getPayload(); // 获取 Token 中的有效载荷
}
/**
* 从 Token 中提取用户名
*/
public String extractUsername(String token) {
return extractClaims(token).getSubject();
}
/**
* 判断 Token 是否过期
* true = 已过期
* false = 未过期
*/
public boolean isExpired(String token) {
return extractClaims(token).getExpiration().before(new Date());
}
}
四、登录接口(返回 Token)
@PostMapping("/api/users/login")
public Result login(@RequestBody User user) {
// 1. 校验用户名密码(你自己写)
User loginUser = userService.getUserByUsername(user.getUsername());
if (loginUser == null || !loginUser.getPassword().equals(user.getPassword())) {
// 你现在收到的错误就是这里!
return Result.fail(401, "用户名或密码错误");
}
// 2. 生成 JWT token
Map<String, Object> claims = new HashMap<>();
claims.put("userId", loginUser.getId());
String token = jwtUtil.generateToken(claims, user.getUsername());
// 3. 返回 token
return Result.success(token);
}
五、前端 axios 携带 Token(你需要的)
axios.post('http://localhost:8080/api/users/login', {
username: 'admin',
password: '123456'
}).then(res => {
const token = res.data;
localStorage.setItem('token', token);
})
// 以后请求携带 token
axios.get('http://localhost:8080/api/user/info', {
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
})