feat(auth): refresh token 续期(B2) — 不透明哈希+单次旋转+/auth/refresh+/auth/logout
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled

- 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:
AskaEth committed 2026-09-08 21:45:00 +08:00
1 parent 7ecb43bd5d
commit 026b27b310
17 files changed
+1237 -13

No files matched your search

+14
View File
@@ -11,6 +11,7 @@ import (
"fmt"
"reflect"
"strings"
"time"
)
// Config is the root configuration tree.
@@ -48,6 +49,19 @@ type AuthConfig struct {
AdminUser string `env:"ADMIN_USERNAME" default:"admin"`
AdminPass string `env:"ADMIN_PASSWORD" default:"admin12345"`
RegistrationEnabled bool `env:"REGISTRATION_ENABLED" default:"true"`
// RefreshTTL is how long an issued opaque refresh token stays valid. It is a
// Go duration string (e.g. "720h" = 30 days). Access tokens keep their 24h
// lifetime; the refresh token is the long-lived credential that renews them.
RefreshTTL time.Duration `env:"AUTH_REFRESH_TTL" default:"720h"`
// RefreshRotateDisabled opts out of single-use refresh rotation. Rotation is
// on by default (the safe default): a successful /auth/refresh revokes the
// presented token and returns a fresh one, so a replayed token fails. Set
// AUTH_REFRESH_ROTATE_DISABLED=true only for clients that cannot persist a
// rotated token. The field is negative-named so its zero value (an
// unset/undecoded config) means rotation is enabled.
RefreshRotateDisabled bool `env:"AUTH_REFRESH_ROTATE_DISABLED" default:"false"`
}
// DBConfig holds database connection settings. SQLite is the default; PGURL is