mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-10 15:26:38 +08:00
优化登录,优化阅读
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -44,12 +45,46 @@ func TestRefreshAcceptsPendingDelayedToken(t *testing.T) {
|
||||
if pair == nil || pair.AccessToken == "" || pair.RefreshToken == "" {
|
||||
t.Fatalf("Refresh returned incomplete pair: %+v", pair)
|
||||
}
|
||||
// 轮换后旧令牌应从 pending 表移除,不能再次使用。
|
||||
// 轮换后旧令牌应从 pending 表移除。
|
||||
if _, still := svc.pendingDelayedStore(hash); still {
|
||||
t.Fatal("rotated pending token still tracked")
|
||||
}
|
||||
if _, err := svc.Refresh(t.Context(), refreshToken); err == nil {
|
||||
t.Fatal("rotated pending token should not refresh twice")
|
||||
// 宽限期内重复提交同一个旧令牌返回同一次轮换的结果(幂等),
|
||||
// 而不是把并发/重试的客户端打成 401 并清空会话。
|
||||
reused, err := svc.Refresh(t.Context(), refreshToken)
|
||||
if err != nil {
|
||||
t.Fatalf("reuse within grace window should be idempotent: %v", err)
|
||||
}
|
||||
if reused.AccessToken != pair.AccessToken || reused.RefreshToken != pair.RefreshToken {
|
||||
t.Fatal("reuse should return the same rotated pair")
|
||||
}
|
||||
}
|
||||
|
||||
// TestRefreshRejectsRotatedTokenAfterGraceWindow 验证宽限期结束后,
|
||||
// 旧令牌仍按已撤销处理(token 复用检测语义不变)。
|
||||
func TestRefreshRejectsRotatedTokenAfterGraceWindow(t *testing.T) {
|
||||
repos := newTokenTestRepo(t)
|
||||
cfg := &config.Config{}
|
||||
cfg.Secrets.JWTSecret = "test-secret"
|
||||
svc := NewTokenService(cfg, zap.NewNop(), repos)
|
||||
|
||||
u := &model.User{Username: "u1", PasswordHash: "x", Role: "user", Tier: "free", IsActive: true}
|
||||
if err := repos.User.Create(t.Context(), u); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pair, err := svc.IssuePair(t.Context(), u.ID, u.Role, u.Tier)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := svc.Refresh(t.Context(), pair.RefreshToken); err != nil {
|
||||
t.Fatalf("first refresh: %v", err)
|
||||
}
|
||||
|
||||
base := time.Now()
|
||||
svc.now = func() time.Time { return base.Add(2 * refreshTokenReuseGrace) }
|
||||
if _, err := svc.Refresh(t.Context(), pair.RefreshToken); !errors.Is(err, ErrTokenRevoked) {
|
||||
t.Fatalf("expired reuse error = %v, want ErrTokenRevoked", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user