无感知自动续期必须采用双 token + redis 状态管理 + 前端 promise 共享方案;jwt.parse 需显式传 jwt.withvalidtime() 才校验 exp;refreshtoken 必须 redis 单次有效、绑定 fingerprint;前端需共享 refreshpromise 避免并发刷新冲突。

无感知自动续期不是靠前端定时刷新或后端延长旧 Token 实现的,必须用双 Token(accessToken + refreshToken)+ Redis 状态管理 + 前端 Promise 共享,缺一不可。
jwt.Parse 默认不校验 exp,必须显式加 jwt.WithValidTime()
很多人发现 token.Valid 总是 true,哪怕 payload 里写了 "exp"——因为 jwt.Parse 默认跳过时间验证。不加这个选项,token.Claims 里的 ExpiresAt 字段也不会被自动解析或校验。
正确写法:
token, err := jwt.Parse(tokenString, keyFunc, jwt.WithValidTime())
if err != nil || !token.Valid {
// 处理过期或无效情况
}
- 别只判断
err,token.Valid必须手动检查 - 如果用的是
jwt.ParseWithClaims,也要传入jwt.WithValidTime() - 校验失败时,不能直接返回 401,要区分是签名错、过期、还是字段缺失
refreshToken 必须存 Redis、单次有效、绑定 fingerprint
JWT 本身无吊销能力。refreshToken 若纯无状态(比如只签个 long-exp 的字符串),泄露即等于永久通行证。
Redis Key 格式建议:refresh:{jti},值为 {user_id}:{fingerprint_hash},其中 fingerprint_hash 推荐用 sha256(fmt.Sprintf("%s:%s", r.UserAgent(), realIP)) 生成。
- 验证时:先
GET,命中则立刻DEL(强制单次使用),再生成新对并写入新jti - 新
refreshToken的exp设为 7 天,但 Redis TTL 必须严格同步该时间 - 漏掉
DEL或复用旧jti,等于开无限续期后门 - 别把
refreshToken塞进 Cookie 自动发——它应走独立 Header,如X-Refresh-Token
前端拦截器必须共享 Promise,不能各自重试
点一次按钮触发多个并发请求,全卡在 401 边界。如果每个都调 /auth/refresh,服务端会生成多对新 Token,前端无法确定哪个有效,Authorization header 覆盖混乱,后续请求大概率 403。
- 维护一个全局变量
refreshPromise,首次 401 时触发刷新并缓存 Promise - 后续同批 401 全部
await refreshPromise,而非发新请求 - 刷新成功后,用新
accessToken重放原始请求;失败则清空登录态(Cookie 或内存 token) - 长连接(WebSocket/gRPC)场景下,服务端需主动预推送新 Token(如
exp前 5 分钟),不能等过期才响应
刷新接口返回的新 refreshToken 必须立即生效,旧值在 Redis 中已不可查
最易被忽略的一点:很多实现只写入新 refreshToken,却忘了删旧 key。
刷新流程必须原子化:
// 伪代码示意
oldJTI := getJTIFromOldRefreshToken()
redis.DEL("refresh:" + oldJTI) // 先删旧
newJTI := generateJTI()
newRT := signRefreshToken(newJTI, userID, fingerprint)
redis.SET("refresh:" + newJTI, value, 7*24*time.Hour)
- 删旧 key 和写新 key 必须在同一个事务或至少保证顺序执行
- 若中间出错(如网络抖动、Redis 写失败),旧 key 未删而新 key 未写,用户将无法续期
- 建议用 Lua 脚本封装 Redis 操作,避免竞态
真正难的不是写刷新逻辑,而是让所有环节严丝合缝:密钥轮换时 keyFunc 要按 kid 动态选密钥;claims 类型断言前必须先判空;refreshToken 的 fingerprint 必须和登录时一致;服务端预推送和前端重试窗口要对齐。任何一环松动,都会在高并发下暴露“多个 401 后突然 403”或用户被踢两次的问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











