JWT 刷新机制改造说明
背景与目标
- 访问 Token 过去 30 分钟即失效,用户必须重新登录,体验较差。
- 本次改造实现 Access Token + Refresh Token 的双 Token 体系,允许用户在长期会话内无感续期,同时保持服务器端对 Refresh Token 的可控性。
主要改动概览
- Token 结构
- 在
JwtUtil中引入TokenType枚举,访问 Token(30 分钟)与刷新 Token(7 天)分别签发。 - Token 负载新增
tokenType,验证时能够区分不同 Token。
- 在
- 缓存策略
USER_LOGIN_KEY:{username}:用户完整信息,TTL 与刷新 Token 一致(7 天)。USER_REFRESH_TOKEN_KEY:{username}:最新刷新 Token 字符串,用于服务端强制失效旧 Token。
- 业务流程
- 登录 (
UserServiceImpl#login):签发 access/refresh token,分别返回给前端,并在 Redis 中落库。 - 刷新 (
UserServiceImpl#refreshToken):校验刷新 Token 是否与 Redis 中一致且未过期,重新签发一对 Token,覆盖 Redis 记录。 - 校验 (
checkLogin):仅接受访问 Token;刷新 Token 不可直接访问受限接口。 - 登出 (
logout):同时清理登录态和刷新 Token。
- 登录 (
- 接口层
- 登录接口返回值扩展为
accessToken、refreshToken、expiresIn。 - 新增
/api/short-link/v1/user/refresh-token提供续期能力。
- 登录接口返回值扩展为
接口详情
1. 登录
POST /api/short-link/v1/user/login
{
"username": "alice",
"password": "******"
}响应:
json
{
"accessToken": "<JWT_ACCESS>",
"refreshToken": "<JWT_REFRESH>",
"expiresIn": 1800000
}2. 刷新 Token
POST /api/short-link/v1/user/refresh-token
{
"refreshToken": "<JWT_REFRESH>"
}响应结构同登录接口,会返回新的 access/refresh token 以及最新的 expiresIn。
3. 校验与登出
GET /api/short-link/v1/user/check-login?username=alice&token=<JWT_ACCESS>DELETE /api/short-link/v1/user/logout?username=alice&token=<JWT_ACCESS>
前端配合方案
- 存储策略
- 登录成功后同时保存
accessToken、refreshToken;expiresIn可用于本地倒计时(毫秒)。 - 建议将刷新 Token 置于
httpOnly Cookie或安全存储,并在切换账号/登出时一并清理。
- 登录成功后同时保存
- 请求拦截
- 所有受保护接口在 Header 中带上
Authorization: Bearer <accessToken>。 - 在发起请求前,如果本地判断
expiresIn即将到期(例如剩余 < 2 分钟),先调用刷新接口拿到新 Token,再继续原请求。
- 所有受保护接口在 Header 中带上
- 自动续期
- 当服务端返回 401/Token 过期错误时:
- 检查本地是否仍持有刷新 Token;
- 调用刷新接口获取新 Token;
- 刷新成功后更新本地缓存并重放原请求;
- 如果刷新失败(返回 401/403/错误码),认为会话失效,跳转登录页并提示用户重新登录。
- 当服务端返回 401/Token 过期错误时:
- 登出
- 调用登出接口后清理本地所有 Token 缓存,避免旧 Token 被继续使用。
- 异常处理
- 刷新接口可能因为会话失效、刷新 Token 被替换或过期而失败,前端需要对此做降级处理(直接退回登录或提示)。
服务端配置步骤回顾
- JWT 工具类
JwtUtil:新增 TokenType、生成/校验逻辑和过期时间常量,暴露getAccessExpirationTime与getRefreshExpirationTime。
- Redis 常量
RedisCacheConstant:新增USER_REFRESH_TOKEN_KEY。
- DTO 调整
- 登录响应
UserLoginRespDTO扩展字段。 - 新建
UserRefreshTokenReqDTO承载刷新请求。
- 登录响应
- Service 层
UserService新增refreshToken抽象。UserServiceImpl登录/校验/登出/刷新逻辑全部适配双 Token。
- Controller
- 新增
/user/refresh-token接口,确保外部可调用刷新能力。
- 新增
- 构建验证
mvn -pl admin -DskipTests package验证admin模块能够成功编译。
测试建议
- 登录后立即调用受保护接口,确保 access token 可用。
- 修改系统时间或等待 30 分钟后,仅凭 refresh token 调用刷新接口,确认能得到新的 access token,并且旧 access token 不再通用。
- 多端登录时,后一次刷新会覆盖 Redis 中的 refresh token,前一次客户端应在刷新失败时触发重新登录。
- 登出后再次使用旧 refresh token 应提示失效。
