中间件安全刷新jwt token的核心是仅在旧token剩余有效期≤600秒时生成新token并立即失效旧token,通过redis原子操作与黑名单机制确保单次有效、状态可控。

中间件里怎么安全地刷新 JWT Token
不能在每次请求都无条件重发新 Token,否则会破坏 Token 的时效控制逻辑。Echo 中间件刷新 Token 的核心是:只在旧 Token 即将过期(比如剩余
常见错误是直接 jwt.Parse 后忽略 Claims.VerifyExpiresAt 检查,导致已过期 Token 被误判为可刷新;或者把新 Token 写进 Set-Cookie 却没设 HttpOnly 和 SameSite,埋下 XSS 或 CSRF 风险。
- 用
jwt.ParseWithClaims解析并显式调用token.Claims.Valid(),不能只靠err == nil - 从
echo.Context取原始 Token 时,优先检查Authorization: Bearer xxx, fallback 到 Cookie(如token字段),避免混用来源导致校验错位 - 新 Token 签发后,建议通过
c.Response().Header().Set("X-Auth-Token", newToken)返回,而非覆盖原 Cookie——前端可自主决定是否更新本地存储
如何让刷新逻辑不干扰业务 Handler
刷新 Token 属于横切关注点,但不能阻断后续处理。典型陷阱是中间件里调用 c.JSON 或 c.String 后忘记 return,导致后续 Handler 仍被执行,引发 “header already written” 错误。
正确做法是用 c.Set 把新 Token 和是否刷新过的信息存到上下文,交由业务 Handler 决定是否返回。比如:
// 中间件内
if shouldRefresh {
newToken, _ := issueNewToken(claims)
c.Set("new_token", newToken)
c.Set("token_refreshed", true)
}
// 不主动响应,继续 next(c)
- 不要在中间件里调用
c.NoContent、c.JSON等响应方法,除非你明确要终止流程(如鉴权失败) - 如果必须立即返回新 Token(如 `/refresh` 接口),那就单独写一个 Handler,别塞进通用鉴权中间件
- 注意
c.Get取值前先用c.IsSet判断,避免 panic
为什么 Refresh Token 不该和 Access Token 放一起用
单纯延长 Access Token 有效期等于放弃“短活期 + 高频校验”的安全设计。真正健壮的方案是分离双 Token:Access Token 短期(15min),Refresh Token 长期(7d)、带存储(Redis)、绑定设备指纹。
通过 Auth0 Token Vault,代表已认证用户访问 Gmail、Slack、Google Calendar、GitHub 等第三方服务以及自定义 Auth0 连接。使用...
Echo 中间件里若只处理 Access Token 刷新,本质是伪刷新——它没解决泄露后持续滥用的问题。真实场景中,中间件应只做 Access Token 校验,而刷新动作必须走独立接口(如 POST /auth/refresh),由该接口验证 Refresh Token 并签发一对新 Token。
- 中间件职责应限定为:
Parse → Verify → SetUser → Continue,不碰 Refresh Token 存储或校验 - 如果硬要在中间件里集成 Refresh Token 验证,必须确保 Redis 查询不阻塞主线程(用
context.WithTimeout包裹) - Refresh Token 一旦使用,必须立即失效(Redis
DEL)并生成新一对,否则存在重放风险
Cookie 和 Header 两种传递方式的实际取舍
用 Cookie 自动携带 Token 简单,但无法细粒度控制刷新时机;用 Authorization Header 需前端配合,却更可控。Echo 中间件里二者处理差异明显:
- Cookie 方式需调用
c.Cookie("token"),注意检查http.SameSiteLaxMode或StrictMode,避免跨站请求时 Cookie 不发送 - Header 方式用
c.Request().Header.Get("Authorization"),记得截掉"Bearer "前缀,空格处理不干净会导致解析失败 - 混合使用时(如 Cookie 存 Refresh Token,Header 传 Access Token),中间件要分两步校验,顺序不能反:先验 Access Token,再按需查 Refresh Token
最易被忽略的是时区与系统时间偏差:服务端用 time.Now().Unix() 校验 exp,但客户端设备时间不准会导致频繁误刷。上线前务必同步 NTP,或在签发时预留几秒缓冲(exp = now.Add(14*time.Minute).Unix() 而非严格 15 分钟)。










