275 lines
7.8 KiB
Markdown
275 lines
7.8 KiB
Markdown
# 企业级JWT加密方案使用指南
|
||
|
||
## 📋 概述
|
||
|
||
本项目已升级到**企业级RSA-256 JWT加密方案**,包含以下特性:
|
||
|
||
### ✅ 核心功能
|
||
- 🔐 **RSA-256非对称加密** - 私钥签名,公钥验证
|
||
- 🔄 **密钥轮换机制** - 支持无缝切换密钥
|
||
- 🛡️ **防重放攻击** - JTI + Redis黑名单
|
||
- 📝 **增强Claims** - ISS/AUD/NBF/JTI完整验证
|
||
- ⚠️ **分类异常处理** - 精确的错误类型识别
|
||
|
||
---
|
||
|
||
## 🚀 快速开始
|
||
|
||
### 1. 生成RSA密钥对
|
||
|
||
运行密钥生成工具:
|
||
|
||
```bash
|
||
# 方式1: 直接运行Java类
|
||
java -cp target/classes com.caiji.uls.utils.jwt.RsaKeyGenerator
|
||
|
||
# 方式2: 运行测试类(推荐)
|
||
.\mvnw.cmd test-compile exec:java -Dexec.mainClass="com.caiji.uls.KeyGenTest"
|
||
```
|
||
|
||
生成的输出类似:
|
||
```
|
||
=== 生成RSA密钥对 ===
|
||
|
||
公钥 (Public Key):
|
||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
||
|
||
私钥 (Private Key):
|
||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC...
|
||
|
||
=== 请将以上密钥配置到 application.properties ===
|
||
jwt.public-key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
|
||
jwt.private-key=MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC...
|
||
```
|
||
|
||
### 2. 配置密钥
|
||
|
||
将生成的密钥复制到 `src/main/resources/application.properties`:
|
||
|
||
```properties
|
||
# JWT Configuration (Enterprise RSA-256)
|
||
jwt.public-key=你的公钥Base64字符串
|
||
jwt.private-key=你的私钥Base64字符串
|
||
jwt.expiration=86400000
|
||
```
|
||
|
||
### 3. 启动应用
|
||
|
||
```bash
|
||
.\mvnw.cmd spring-boot:run
|
||
```
|
||
|
||
启动成功后会看到:
|
||
```
|
||
[JWT] RSA密钥配置已初始化
|
||
[JWT] 过期时间: 86400000 毫秒 (1440 分钟)
|
||
[JWT] 签名算法: RS256 (RSA-SHA256)
|
||
```
|
||
|
||
---
|
||
|
||
## 💡 使用示例
|
||
|
||
### 生成Token
|
||
|
||
```java
|
||
import com.caiji.uls.utils.jwt.JwtUtil;
|
||
|
||
// 基础用法
|
||
String token = JwtUtil.generateToken(userId, username);
|
||
|
||
// 带额外声明
|
||
Map<String, Object> claims = new HashMap<>();
|
||
claims.put("role", "admin");
|
||
claims.put("department", "IT");
|
||
String token = JwtUtil.generateToken(userId, username, claims);
|
||
```
|
||
|
||
### 验证Token
|
||
|
||
```java
|
||
import com.caiji.uls.utils.jwt.JwtUtil;
|
||
import com.caiji.uls.utils.jwt.TokenBlacklistService;
|
||
|
||
@Autowired
|
||
private TokenBlacklistService blacklistService;
|
||
|
||
// 基础验证(仅验证签名和格式)
|
||
boolean isValid = JwtUtil.validateToken(token);
|
||
|
||
// 完整验证(包含黑名单检查)
|
||
boolean isValid = JwtUtil.validateToken(token, blacklistService);
|
||
|
||
// 提取用户信息
|
||
String userId = JwtUtil.getUserIdFromToken(token);
|
||
String username = JwtUtil.getUsernameFromToken(token);
|
||
String jti = JwtUtil.getJtiFromToken(token);
|
||
```
|
||
|
||
### Token注销(加入黑名单)
|
||
|
||
```java
|
||
@Autowired
|
||
private TokenBlacklistService blacklistService;
|
||
|
||
// 获取Token的JTI
|
||
String jti = JwtUtil.getJtiFromToken(token);
|
||
|
||
// 计算剩余有效期(秒)
|
||
long remainingTime = JwtUtil.getTokenRemainingTime(token);
|
||
|
||
// 加入黑名单
|
||
blacklistService.addToBlacklist(jti, remainingTime);
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 高级功能
|
||
|
||
### 密钥轮换
|
||
|
||
```java
|
||
import com.caiji.uls.utils.jwt.JwtKeyManager;
|
||
|
||
// 生成新密钥对
|
||
var newKeyPair = RsaKeyGenerator.generateKeyPair();
|
||
String newPublicKey = RsaKeyGenerator.encodePublicKey((RSAPublicKey) newKeyPair.getPublic());
|
||
String newPrivateKey = RsaKeyGenerator.encodePrivateKey((RSAPrivateKey) newKeyPair.getPrivate());
|
||
|
||
// 执行轮换(旧密钥仍可用于验证)
|
||
JwtKeyManager.rotateKeys(newPublicKey, newPrivateKey);
|
||
|
||
// 过渡期后清除旧密钥(建议7-30天后)
|
||
JwtKeyManager.clearPreviousKey();
|
||
```
|
||
|
||
### 自定义Claims验证
|
||
|
||
```java
|
||
import io.jsonwebtoken.Claims;
|
||
|
||
Claims claims = JwtUtil.getClaimsFromToken(token);
|
||
|
||
// 获取标准字段
|
||
String issuer = claims.getIssuer(); // 签发者
|
||
String audience = claims.getAudience(); // 受众
|
||
Date issuedAt = claims.getIssuedAt(); // 签发时间
|
||
Date expiration = claims.getExpiration(); // 过期时间
|
||
|
||
// 获取自定义字段
|
||
String userId = claims.get("userId", String.class);
|
||
String role = claims.get("role", String.class);
|
||
```
|
||
|
||
---
|
||
|
||
## 🛡️ 安全特性
|
||
|
||
### 1. RSA-256签名
|
||
- **私钥签名**:只有认证服务器持有私钥
|
||
- **公钥验证**:可分发公钥给多个微服务
|
||
- **防篡改**:任何修改都会导致签名验证失败
|
||
|
||
### 2. Claims增强
|
||
| 字段 | 说明 | 用途 |
|
||
|------|------|------|
|
||
| `iss` | 签发者 | 防止伪造Token |
|
||
| `aud` | 受众 | 限制Token使用范围 |
|
||
| `nbf` | Not Before | 防止时钟偏移攻击 |
|
||
| `jti` | JWT ID | 唯一标识,防重放 |
|
||
| `iat` | Issued At | 签发时间追踪 |
|
||
| `exp` | Expiration | 自动过期 |
|
||
|
||
### 3. Redis黑名单
|
||
- **即时注销**:用户登出后立即失效
|
||
- **密码修改保护**:修改密码后所有Token失效
|
||
- **自动清理**:Redis TTL自动删除过期条目
|
||
|
||
### 4. 异常分类
|
||
| 异常类型 | HTTP状态码 | 说明 |
|
||
|----------|-----------|------|
|
||
| `JwtTokenExpiredException` | 401 | Token已过期 |
|
||
| `JwtSignatureInvalidException` | 401 | 签名无效 |
|
||
| `JwtMalformedException` | 400 | 格式错误 |
|
||
| `JwtTokenBlacklistedException` | 401 | 已被注销 |
|
||
|
||
---
|
||
|
||
## ⚙️ 配置项说明
|
||
|
||
```properties
|
||
# RSA公钥(Base64编码)
|
||
jwt.public-key=YOUR_PUBLIC_KEY
|
||
|
||
# RSA私钥(Base64编码,务必保密!)
|
||
jwt.private-key=YOUR_PRIVATE_KEY
|
||
|
||
# Token过期时间(毫秒),默认24小时
|
||
jwt.expiration=86400000
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 架构优势对比
|
||
|
||
| 特性 | 旧版(HMAC) | 新版(RSA) |
|
||
|------|-------------|------------|
|
||
| 加密算法 | HS256对称加密 | RS256非对称加密 |
|
||
| 密钥管理 | 单密钥硬编码 | 密钥对+轮换机制 |
|
||
| 多服务支持 | ❌ 需共享密钥 | ✅ 只需分发公钥 |
|
||
| 防重放攻击 | ❌ 无 | ✅ JTI+黑名单 |
|
||
| Claims验证 | 基础 | ISS/AUD/NBF完整验证 |
|
||
| 密钥泄露风险 | ⚠️ 高 | ✅ 低(私钥不泄露) |
|
||
| 企业合规 | ❌ 不符合 | ✅ 符合OWASP标准 |
|
||
|
||
---
|
||
|
||
## 🔍 故障排查
|
||
|
||
### 问题1: 启动时提示"未检测到RSA密钥配置"
|
||
**原因**: `application.properties`中未配置密钥
|
||
**解决**: 运行密钥生成工具并配置密钥
|
||
|
||
### 问题2: Token验证失败"签名无效"
|
||
**原因**: 密钥不匹配或Token被篡改
|
||
**解决**:
|
||
1. 确认公钥/私钥配置正确
|
||
2. 检查Token是否完整传输
|
||
3. 查看日志中的Key ID是否匹配
|
||
|
||
### 问题3: Redis连接失败
|
||
**原因**: Redis服务未启动或配置错误
|
||
**解决**: 检查`application.properties`中的Redis配置
|
||
|
||
---
|
||
|
||
## 📚 相关文件
|
||
|
||
- **密钥生成**: [RsaKeyGenerator.java](file:///D:/ClassDev/Spring/uni_login_system/src/main/java/com/caiji/uls/utils/jwt/RsaKeyGenerator.java)
|
||
- **密钥管理**: [JwtKeyManager.java](file:///D:/ClassDev/Spring/uni_login_system/src/main/java/com/caiji/uls/utils/jwt/JwtKeyManager.java)
|
||
- **JWT工具**: [JwtUtil.java](file:///D:/ClassDev/Spring/uni_login_system/src/main/java/com/caiji/uls/utils/jwt/JwtUtil.java)
|
||
- **黑名单服务**: [TokenBlacklistService.java](file:///D:/ClassDev/Spring/uni_login_system/src/main/java/com/caiji/uls/utils/jwt/TokenBlacklistService.java)
|
||
- **配置初始化**: [JwtConfigInitializer.java](file:///D:/ClassDev/Spring/uni_login_system/src/main/java/com/caiji/uls/config/JwtConfigInitializer.java)
|
||
- **异常处理**: [JwtGlobalExceptionHandler.java](file:///D:/ClassDev/Spring/uni_login_system/src/main/java/com/caiji/uls/config/JwtGlobalExceptionHandler.java)
|
||
|
||
---
|
||
|
||
## 🎯 最佳实践
|
||
|
||
1. **生产环境必须配置固定密钥对**,不要使用自动生成的临时密钥
|
||
2. **私钥严格保密**,不要提交到版本控制系统
|
||
3. **定期轮换密钥**(建议每30-90天)
|
||
4. **监控黑名单大小**,异常增长可能表示安全问题
|
||
5. **设置合理的过期时间**,平衡安全性和用户体验
|
||
6. **HTTPS传输**,防止Token被中间人窃取
|
||
|
||
---
|
||
|
||
## 📞 技术支持
|
||
|
||
如有问题,请检查:
|
||
1. 应用启动日志中的JWT初始化信息
|
||
2. Redis连接状态
|
||
3. 密钥配置是否正确
|
||
4. Token格式是否符合JWT标准(三段式Base64)
|