Spring Boot整合JWT 实现双Token机制
目录
- JWT核心概念解析
- Spring Boot整合步骤
- 2.1 基础环境搭建
- 2.2 Token生成与解析
- 2.3 拦截器实现
- 企业级增强方案
- 3.1 双Token刷新机制
- 3.2 安全防护策略
- 常见问题与解决方案
1. JWT核心概念解析
1.1 Token的三重使命
- 身份凭证:替代Session实现无状态认证
- 信息载体:存储用户基础信息(如userid、roles)
- 安全屏障:数字签名防止数据篡改
1.2 JWT结构示例
Header
{"alg": "HS256","typ": "JWT"
}Payload
{"sub": "123456","name": "John","iat": 1516239022
}Signature
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
2. Spring Boot整合步骤
2.1 基础环境搭建
依赖配置:
<!-- pom.xml -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
配置文件:
# application.yml
jwt:secret: your-256-bit-encryption-keyexpiration: 7200 # 2小时header: Authorization
2.2 Token生成与解析
工具类实现:
@Component
public class JwtUtils {// 注入配置参数@Value("${jwt.secret}")private String secret;// 生成Tokenpublic String generateToken(UserDetails user) {return Jwts.builder().setSubject(user.getUsername()).claim("roles", user.getAuthorities()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + expiration * 1000)).signWith(SignatureAlgorithm.HS256, secret).compact();}// 解析Tokenpublic Claims parseToken(String token) {return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();}
}
2.3 拦截器实现
认证拦截器:
public class JwtInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 1. 检查白名单路径if (isWhiteList(request.getRequestURI())) {return true;}// 2. 获取并验证TokenString token = request.getHeader(jwtProperties.getHeader());if (!jwtUtils.validateToken(token)) {throw new UnauthorizedException("无效的访问凭证");}// 3. 注入用户信息Claims claims = jwtUtils.parseToken(token);request.setAttribute("userId", claims.getSubject());return true;}private boolean isWhiteList(String uri) {return Arrays.asList("/api/login", "/api/refresh").contains(uri);}
}
注册拦截器:
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(jwtInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/auth/**");}
}
3. 企业级增强方案
3.1 双Token刷新机制
流程图解:
刷新接口实现:
@PostMapping("/refresh")
public Result refreshToken(@RequestParam String refreshToken) {if (redisTemplate.hasKey(refreshToken)) {String username = redisTemplate.opsForValue().get(refreshToken);UserDetails user = userService.loadUserByUsername(username);String newAccessToken = jwtUtils.generateToken(user);return Result.ok().data("accessToken", newAccessToken);}throw new BusinessException(600, "刷新令牌已失效");
}
3.2 安全防护策略
五层防御体系:
- 传输加密:强制使用HTTPS
- 存储安全:前端使用HttpOnly Cookie
- 自动续期:Access Token有效期≤2小时
- 黑名单:登出Token立即失效
- 限流控制:接口请求频率限制
黑名单实现:
@Component
public class TokenBlacklist {@Autowiredprivate RedisTemplate<String, String> redisTemplate;// Token加入黑名单(有效期剩余时间)public void addToBlacklist(String token) {Date expiration = jwtUtils.getExpirationFromToken(token);long ttl = expiration.getTime() - System.currentTimeMillis();redisTemplate.opsForValue().set(token, "invalid", ttl, TimeUnit.MILLISECONDS);}
}
4. 常见问题与解决方案
问题现象 | 根本原因 | 解决方案 |
---|---|---|
签名验证失败 | 密钥不一致或Token被篡改 | 统一密钥管理(配置中心) |
Token突然失效 | 服务器时间不同步 | 部署NTP时间同步服务 |
高并发下认证超时 | RSA算法性能瓶颈 | 切换为HS256算法 |
无法强制下线已登录用户 | 无状态特性导致 | 结合Redis维护短期Token黑名单 |
总结:JWT为现代分布式系统提供了优雅的认证解决方案,但实际落地时需综合考虑安全、性能、用户体验等多维度因素。建议结合具体业务场景选择合适的Token管理策略。