文章目录
- [一、什么是 JWT?](#一、什么是 JWT?)
- [二、为什么 JWT 是无状态的?](#二、为什么 JWT 是无状态的?)
- 三、无状态有什么优点?
- [四、JWT 的组成结构](#四、JWT 的组成结构)
- [五、Spring Boot 实战案例:JWT 登录认证](#五、Spring Boot 实战案例:JWT 登录认证)
- [六、Token 泄漏怎么办?](#六、Token 泄漏怎么办?)
- 七、总结
一、什么是 JWT?
JWT,全称 JSON Web Token,是一种基于 JSON 的安全认证机制,常用于前后端分离项目中实现用户身份认证。
JWT 的核心思想是:
"服务器签发令牌(Token),客户端保存并携带该令牌完成身份验证。"
相比传统的 Session 机制,JWT 最大的不同在于它是 无状态的 ------ 服务器不再保存用户登录状态。
二、为什么 JWT 是无状态的?
在传统 Session 认证中:
- 用户登录成功 → 服务器创建
session并保存到内存中; - 返回一个
sessionId给浏览器; - 浏览器每次请求都带上
sessionId; - 服务器根据
sessionId查询用户信息。
这样一来,服务器需要保存大量 session 状态,不利于分布式部署。
而 JWT 则不同:
- 登录后,服务器直接生成一段 加密签名的 Token;
- 客户端保存这个 Token(通常存在 localStorage 或 Cookie 中);
- 下次请求时,客户端在
Authorization头中带上该 Token; - 服务器通过验证签名即可确认身份,而无需查数据库。
👉 因此,JWT 是 无状态的(Stateless),服务器不保存会话信息。
三、无状态有什么优点?
| 优点 | 说明 |
|---|---|
| ✅ 可扩展性强 | 不依赖服务器内存,天然支持分布式和微服务架构。 |
| ✅ 服务器负担小 | 无需保存 Session 数据,减少内存和存储开销。 |
| ✅ 跨服务共享认证 | 不同服务共享同一 JWT,无需集中 Session 管理。 |
| ✅ 适合前后端分离 | 前端存储 Token 即可携带身份信息。 |
四、JWT 的组成结构
一个 JWT 由三部分组成,用 . 分隔:
Header.Payload.Signature
例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOiIxMjM0NSIsIm5hbWUiOiJKb2huIERvZSJ9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
1、Header(头部)
声明加密算法和类型:
json
{
"alg": "HS256",
"typ": "JWT"
}
2、Payload(载荷)
包含用户信息和自定义数据:
json
{
"userId": "12345",
"role": "admin",
"exp": 1734129600
}
⚠️ 注意:Payload 是 明文可解码的,不要放敏感信息(如密码)。
3、Signature(签名)
签名用于防止数据被篡改:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
五、Spring Boot 实战案例:JWT 登录认证
下面用一个简单的 Spring Boot 项目演示 JWT 登录认证。
1、添加依赖
在 pom.xml 中加入:
xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
2、JWT 工具类
java
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import java.util.Date;
public class JwtUtil {
private static final String SECRET_KEY = "mySecretKeyForJwt1234567890"; // 自定义密钥
private static final long EXPIRATION_TIME = 1000 * 60 * 60; // 1小时
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()))
.compact();
}
public static String validateToken(String token) {
try {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY.getBytes())
.build()
.parseClaimsJws(token)
.getBody()
.getSubject();
} catch (JwtException e) {
return null; // Token 无效
}
}
}
3、登录接口示例
java
@RestController
@RequestMapping("/auth")
public class AuthController {
@PostMapping("/login")
public Map<String, String> login(@RequestBody Map<String, String> user) {
String username = user.get("username");
String password = user.get("password");
// 简单演示:假设账号密码固定
if ("admin".equals(username) && "123456".equals(password)) {
String token = JwtUtil.generateToken(username);
return Map.of("token", token);
} else {
return Map.of("error", "用户名或密码错误");
}
}
@GetMapping("/profile")
public Map<String, Object> profile(@RequestHeader("Authorization") String token) {
String username = JwtUtil.validateToken(token);
if (username != null) {
return Map.of("user", username, "msg", "验证成功");
} else {
return Map.of("error", "Token无效或已过期");
}
}
}
请求示例:
✅ 登录成功:
POST /auth/login
{
"username": "admin",
"password": "123456"
}
返回:
json
{
"token": "eyJhbGciOiJIUzI1NiIsInR5..."
}
✅ 访问个人信息:
GET /auth/profile
Header: Authorization: eyJhbGciOiJIUzI1NiIsInR5...
六、Token 泄漏怎么办?
JWT 一旦泄露,攻击者可以冒充用户,因此必须采取以下措施:
- 启用 HTTPS:防止中间人窃取 Token。
- 缩短 Token 有效期,如 15 分钟。
- 使用 Refresh Token 机制 实现自动续签。
- 服务端引入黑名单(Blacklist)机制:在 Token 泄露后立即失效。
- 轮换密钥(Secret):定期更换签名密钥,旧 Token 立即失效。
- 记录设备信息或签发时间:服务端可拒绝过期或异常登录。
七、总结
| 内容 | 说明 |
|---|---|
| JWT 本质 | 一种无状态的 Token 认证机制 |
| 无状态好处 | 可扩展、轻量、高性能 |
| 核心组成 | Header、Payload、Signature |
| 安全防护 | HTTPS、短期 Token、黑名单机制 |
| 实战应用 | Spring Boot + JJWT 完成登录认证 |
💡 一句话总结:
JWT 用"签名"替代了"会话存储",让认证更轻、更快、更适合分布式系统。