JWT 全面解析与 Spring Boot 实战教程
JWT 全面解析与 Spring Boot 实战教程
一、JWT 简介
JWT(JSON Web Token) 是一种基于 JSON 的 轻量级无状态认证令牌,常用于前后端分离和微服务系统中。
它将用户身份信息和签名一起打包,可以被客户端保存并在后续请求中携带,从而实现无状态认证。
JWT 组成
JWT 由三部分组成,用点 . 分隔:
Header.Payload.Signature
-
Header(头部)
-
描述签名算法和令牌类型
-
常见字段:
{"alg": "HS256","typ": "JWT" }
-
-
Payload(载荷)
-
存储声明(Claims),包括标准 Claims 和自定义 Claims
-
标准 Claims:
iss(Issuer):签发人sub(Subject):主题aud(Audience):接收方exp(Expiration Time):过期时间nbf(Not Before):生效时间iat(Issued At):签发时间jti(JWT ID):唯一标识
-
自定义 Claims:业务相关字段,如用户角色、ID、权限等
-
-
Signature(签名)
- 使用算法对 Header + Payload + Secret(或私钥)签名
- 作用:防止数据被篡改
示例 Token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiJ1c2VyMSIsImlhdCI6MTY5NzU0MzYwMCwiZXhwIjoxNjk3NTQ3MjAwfQ
.
s5E7nEJ-Tp8kYmIiwzS3i_fzIDz5gXybR5Z7dgh
可以 Base64 解码 Header 和 Payload,查看信息,但 Signature 保证了其不可伪造性。
二、JWT 工作原理
-
用户登录:用户提交用户名和密码
-
服务器验证:验证通过后生成 JWT
-
客户端存储 Token:通常存在 LocalStorage 或 Cookie
-
客户端请求接口:在请求头
Authorization: Bearer <token>携带 Token -
服务器验证 Token:
- 校验签名是否正确
- 校验是否过期或未生效
-
响应结果:验证通过允许访问,失败返回 401/403
对比传统 Session:
| 特性 | Session | JWT |
|---|---|---|
| 状态存储 | 服务器保存 | 客户端保存 |
| 扩展性 | 受限于服务器 | 高,可跨服务 |
| 跨域 | 较复杂 | 简单(HTTP Header 携带) |
| 安全性 | 需要保护 SessionID | 需要保护 Secret + HTTPS |
三、JWT 的使用场景
- 前后端分离登录认证
- 微服务之间身份传递
- 单点登录(SSO)
- 第三方系统授权(OAuth2 Access Token)
四、JWT 优缺点分析
优点:
- 无状态,无需服务器存储 session
- 可跨域、跨服务使用
- 可携带自定义信息,减少额外请求
缺点:
- 无法主动失效(Token 被盗用无法立即作废)
- Token 基于 Base64 编码,容易被解码(但不能伪造签名)
- Token 体积较大,不适合存储大量信息
五、Java 中 JWT 实现
这里以 java-jwt(Auth0) 为例,也可选择 jjwt。
1. Maven 依赖
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version>
</dependency>
2. 生成 JWT
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;public class JwtUtils {private static final String SECRET = "mySecretKey";// 生成 JWTpublic static String generateToken(String username, int userId) {Algorithm algorithm = Algorithm.HMAC256(SECRET);return JWT.create().withIssuer("my-app") // 签发者.withSubject(username) // 用户名.withClaim("userId", userId) // 自定义字段.withClaim("role", "admin") // 用户角色.withIssuedAt(new Date()) // 签发时间.withExpiresAt(new Date(System.currentTimeMillis() + 3600_000)) // 1小时过期.sign(algorithm);}
}
3600_000表示 3600 秒 × 1000 毫秒 = 1 小时,下划线提高可读性。
3. 验证与解析 JWT
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;public class JwtVerify {private static final String SECRET = "mySecretKey";public static void verifyToken(String token) {Algorithm algorithm = Algorithm.HMAC256(SECRET);JWTVerifier verifier = JWT.require(algorithm).withIssuer("my-app").build();DecodedJWT jwt = verifier.verify(token);System.out.println("用户名:" + jwt.getSubject());System.out.println("用户ID:" + jwt.getClaim("userId").asInt());System.out.println("角色:" + jwt.getClaim("role").asString());System.out.println("过期时间:" + jwt.getExpiresAt());}
}
六、Spring Boot 集成 JWT
1. 登录接口签发 Token
@RestController
@RequestMapping("/auth")
public class AuthController {@PostMapping("/login")public String login(@RequestParam String username, @RequestParam String password) {// TODO: 验证用户名密码return JwtUtils.generateToken(username, 123);}
}
2. 拦截器/Filter 校验 Token
@Component
public class JwtInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String authHeader = request.getHeader("Authorization");if (authHeader == null || !authHeader.startsWith("Bearer ")) {response.setStatus(401);return false;}try {String token = authHeader.substring(7);JwtVerify.verifyToken(token);return true;} catch (Exception e) {response.setStatus(401);return false;}}
}
可在
WebMvcConfigurer中注册拦截器,设置忽略/login,/register等无需认证路径。
七、JWT 使用注意事项
-
密钥管理
- 不要硬编码,建议从环境变量或配置中心读取
-
过期时间
- Token 不宜永久有效,可结合 Refresh Token 延长会话
-
敏感信息
- 不要存储密码或银行卡等敏感信息
-
HTTPS 传输
- 防止中间人攻击
-
可控失效机制
- 可结合 Redis 黑名单实现强制登出
-
刷新机制
- 过期前刷新 Token,保证用户体验
八、JWT 与 OAuth2、Session 的关系
-
JWT ≠ OAuth2
- JWT 是令牌格式
- OAuth2 是认证授权协议,Access Token 可以使用 JWT 格式
-
JWT 与 Session 对比
- Session:服务端有状态
- JWT:客户端持有状态,无需服务器存储
九、扩展与优化实践
- JWT + Redis 黑名单:可实现强制 Token 作废
- RS256 公私钥签名:更安全,避免共享密钥
- 自定义 Claims:可放权限列表、角色、部门信息
- 数组 Claims:适合多角色或权限管理
.withArrayClaim("permissions", new String[]{"read","write","delete"});
-
调试与工具:
- jwt.io → 可以在线解码 Token
十、总结
- JWT 是轻量级、无状态的认证机制
- 前端携带 Token 访问接口,后端只需验证签名即可
- 适合前后端分离、微服务、单点登录
- 注意安全实践:密钥管理、过期时间、HTTPS、刷新机制
- 在 Java / Spring Boot 中使用 java-jwt 或 jjwt 都非常方便
