feat(auth): refresh token 续期(B2) — 不透明哈希+单次旋转+/auth/refresh+/auth/logout
- auth/refresh.go: RefreshStore(Issue/Rotate/Revoke/RevokeAll/RevokeByUser), SHA-256哈希256-bit随机串, 单次旋转事务(并发重放fail-closed) - 迁移0008_refresh_tokens(id/user_id/role/token_hash UNIQUE/expires_at/revoked_at + 索引) - gateway: POST /v1/auth/refresh(旋转/续期) + /v1/auth/logout(单/全设备); login响应增refreshToken - config: AUTH_REFRESH_TTL(720h)/AUTH_REFRESH_ROTATE_DISABLED; decode.go 支持time.Duration - rotate-jwt成功后RevokeAll(响应refreshTokensRevoked), revoke-keys不动refresh - 14测试+真实二进制e2e, build/vet/test绿+交叉编译 - Docs/api-client v0.25 + api-reference §2.3/2.4 同步
This commit is contained in:
1 parent
7ecb43bd5d
commit
026b27b310
17 files changed
+1237
-13
No files matched your search
@@ -71,10 +71,27 @@ func (s *Server) adminRotateJWT(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, apperr.Wrap(apperr.ErrInternal, "rotate_failed", "failed to rotate jwt secret"))
|
||||
return
|
||||
}
|
||||
// Credential rotation must invalidate every long-lived grant too, not only the
|
||||
// access tokens signed under the old secret. Refresh tokens are opaque and
|
||||
// secret-independent, so they are deleted wholesale — the minimal, exact
|
||||
// global invalidation in this architecture (no token_version column needed).
|
||||
var refreshRevoked int64
|
||||
if s.refresh != nil {
|
||||
n, rerr := s.refresh.RevokeAll(r.Context())
|
||||
if rerr != nil {
|
||||
s.log.Error("rotate-jwt revoke refresh tokens", "err", rerr)
|
||||
s.auditClaims(r, "system.rotate_jwt", "error")
|
||||
writeError(w, apperr.Wrap(apperr.ErrInternal, "refresh_revoke_failed",
|
||||
"JWT 已轮换,但 refresh token 作废失败,请重试或检查数据库"))
|
||||
return
|
||||
}
|
||||
refreshRevoked = n
|
||||
}
|
||||
s.auditClaims(r, "system.rotate_jwt", "ok")
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"rotated": true,
|
||||
"note": "现有 token 已全部失效,需重新登录",
|
||||
"rotated": true,
|
||||
"refreshTokensRevoked": refreshRevoked,
|
||||
"note": "现有 token 与 refresh token 已全部失效,需重新登录",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user