Beego 中需在 Prepare 方法或自定义 Filter 中拦截请求,判断 AccessToken 是否临近过期(如剩余不足5分钟),若满足则签发新 Token 并响应,实现无感续期。

Beego 里 JWT 过期后不能靠前端定时刷,必须由后端在每次请求中动态判断并响应新 AccessToken —— 否则用户闲置 30 分钟后点一下按钮就 401,根本谈不上“无感”。
Beego 中如何拦截请求并触发 AccessToken 自动续期
Beego 没有类似 Spring Security 的 OnTokenValidated 钩子,得手动在 Prepare 方法或自定义 Filter 里做。关键不是“有没有过期”,而是“是否快过期”。比如 Access Token 设为 30 分钟,当剩余有效期
- 用
jwt.ParseWithClaims解析请求头中的Authorization: Bearer xxx,拿到exp字段 - 计算
exp - time.Now().Unix(),若结果 createAccessToken 生成新 Token - 把新 Token 放进响应头:
this.Ctx.ResponseWriter.Header().Set("X-Access-Token", newToken) - 前端 Axios 拦截器监听这个 header,自动更新本地存储的
access_token
Refresh Token 必须存在 HttpOnly Cookie 而非 localStorage
Beego 默认不强制 Cookie 安全策略,但如果你把 refresh_token 存在 localStorage,XSS 攻击下它会被 JS 直接读走 —— 这等于把长期有效的凭证明文暴露。正确做法是服务端用 this.Ctx.SetCookie 写入,并显式设置安全属性:
-
maxAge设为 Refresh Token 的实际过期秒数(如 7 天 = 604800) -
secure设为true(仅 HTTPS 传输) -
httpOnly设为true(JS 无法读取) -
sameSite推荐"Strict"或"Lax",防 CSRF
登录成功后不要只返回 JSON,要同步写 Cookie:this.Ctx.SetCookie("refresh_token", rtoken, 604800, "/", "yourdomain.com", true, true)
Refresh Token 复用漏洞:Beego 里怎么防重放攻击
JWT 本身无状态,但 Refresh Token 续期必须有状态 —— 否则攻击者截获一次 /auth/refresh 请求,就能无限换新 AccessToken。Beego Controller 里处理刷新接口时,必须查库校验:
- 数据库表要有
jti(JWT 唯一 ID)、user_id、is_used、expires_at字段 - 收到刷新请求后,先查
jti是否已存在且is_used == false - 验证通过后,立刻执行
UPDATE ... SET is_used = true,并用SELECT ... FOR UPDATE加行锁防并发 - 别省略
ValidateToken里的jti校验逻辑,否则refresh_token就是裸奔
Beego 的 JWT 解析容易忽略时区与时间精度问题
Go 默认用本地时区解析时间戳,而 JWT 的 exp 是 UTC 时间。如果服务器时区不是 UTC,time.Unix(exp, 0).Before(time.Now()) 可能误判过期。更稳妥的做法是:
- 用
time.Unix(exp, 0).In(time.UTC)强制转为 UTC 时间再比对 - 避免直接用
time.Now().Unix()做比较,改用time.Now().UTC().Unix() - Beego 日志里打时间戳时也统一用
time.Now().UTC().Format(...),方便排查
真正难的不是签 Token,而是让每个环节都默认按 UTC 对齐 —— 差一秒,就可能在高峰期出现大量“刚续完又 401”的假象。


















