feat(auth): JWT 滑动续期 + 401 自动登出,修复长挂机莫名掉线

- 后端:JWT 有效期可配(JWT_EXPIRE_HOURS,默认 24h);令牌寿命过半时经
  X-Renewed-Token 响应头滑动续期;新增 POST /api/auth/refresh 以数据库真实身份签发
- 前端 request 层:静默接管续期头并同步 localStorage;任何 401(登录/续期除外)
  统一广播会话过期事件
- auth store:监听过期事件清理登录态并跳转 /login?expired=1(不再卡 403 页);
  每 10 分钟定时续期,避免 WS 重连时令牌已过期
- 新增滑动续期单元测试(回签过期时间戳),go test -race 通过
This commit is contained in:
yml2213
2026-09-05 15:57:42 +08:00
parent 223d30efd0
commit e675f427a7
10 changed files with 277 additions and 17 deletions
+6 -4
View File
@@ -56,10 +56,12 @@ func SetupRoutes(r *gin.Engine, store storage.ObjectStorage, storageCfg config.S
authRequired := api.Group("")
authRequired.Use(middleware.AuthRequired())
{
// 当前用户
authRequired.GET("/me", auth.Me)
authRequired.GET("/me/permissions", auth.MePermissions)
authRequired.PUT("/me/status", auth.UpdatePresence)
// 当前用户
authRequired.GET("/me", auth.Me)
authRequired.GET("/me/permissions", auth.MePermissions)
authRequired.PUT("/me/status", auth.UpdatePresence)
// 令牌续期(前端定时调用,防止长挂机后过期掉线)
authRequired.POST("/auth/refresh", auth.Refresh)
// WebSocket
authRequired.GET("/ws", wsHandler.Connect)