fix(auth): preserve resolved token version on oauth login
This commit is contained in:
@@ -778,6 +778,14 @@ func TestExchangePendingOAuthCompletionExistingLoginWithSuggestedProfileSkipsAdo
|
|||||||
require.Equal(t, "https://cdn.example/existing-login.png", payload["suggested_avatar_url"])
|
require.Equal(t, "https://cdn.example/existing-login.png", payload["suggested_avatar_url"])
|
||||||
require.NotContains(t, payload, "adoption_required")
|
require.NotContains(t, payload, "adoption_required")
|
||||||
|
|
||||||
|
accessToken, ok := payload["access_token"].(string)
|
||||||
|
require.True(t, ok)
|
||||||
|
claims, err := handler.authService.ValidateToken(accessToken)
|
||||||
|
require.NoError(t, err)
|
||||||
|
reloadedUser, err := handler.userService.GetByID(ctx, userEntity.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, reloadedUser.TokenVersion, claims.TokenVersion)
|
||||||
|
|
||||||
decisionCount, err := client.IdentityAdoptionDecision.Query().
|
decisionCount, err := client.IdentityAdoptionDecision.Query().
|
||||||
Where(identityadoptiondecision.PendingAuthSessionIDEQ(session.ID)).
|
Where(identityadoptiondecision.PendingAuthSessionIDEQ(session.ID)).
|
||||||
Count(ctx)
|
Count(ctx)
|
||||||
@@ -2033,6 +2041,13 @@ func TestLogin2FACompletesPendingOAuthBindAndConsumesSession(t *testing.T) {
|
|||||||
payload := decodeJSONResponseData(t, recorder)
|
payload := decodeJSONResponseData(t, recorder)
|
||||||
require.NotEmpty(t, payload["access_token"])
|
require.NotEmpty(t, payload["access_token"])
|
||||||
require.NotEmpty(t, payload["refresh_token"])
|
require.NotEmpty(t, payload["refresh_token"])
|
||||||
|
accessToken, ok := payload["access_token"].(string)
|
||||||
|
require.True(t, ok)
|
||||||
|
claims, err := handler.authService.ValidateToken(accessToken)
|
||||||
|
require.NoError(t, err)
|
||||||
|
reloadedUser, err := handler.userService.GetByID(ctx, existingUser.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, reloadedUser.TokenVersion, claims.TokenVersion)
|
||||||
|
|
||||||
identity, err := client.AuthIdentity.Query().
|
identity, err := client.AuthIdentity.Query().
|
||||||
Where(
|
Where(
|
||||||
|
|||||||
@@ -1500,6 +1500,9 @@ func resolvedTokenVersion(user *User) int64 {
|
|||||||
if user == nil {
|
if user == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
if user.TokenVersionResolved {
|
||||||
|
return user.TokenVersion
|
||||||
|
}
|
||||||
|
|
||||||
material := strings.ToLower(strings.TrimSpace(user.Email)) + "\n" + user.PasswordHash
|
material := strings.ToLower(strings.TrimSpace(user.Email)) + "\n" + user.PasswordHash
|
||||||
sum := sha256.Sum256([]byte(material))
|
sum := sha256.Sum256([]byte(material))
|
||||||
|
|||||||
@@ -23,12 +23,15 @@ type User struct {
|
|||||||
Status string
|
Status string
|
||||||
AllowedGroups []int64
|
AllowedGroups []int64
|
||||||
TokenVersion int64 // Incremented on password change to invalidate existing tokens
|
TokenVersion int64 // Incremented on password change to invalidate existing tokens
|
||||||
SignupSource string
|
// TokenVersionResolved indicates TokenVersion already contains the fingerprint-derived
|
||||||
LastLoginAt *time.Time
|
// value expected in JWT claims and refresh-token state.
|
||||||
LastActiveAt *time.Time
|
TokenVersionResolved bool
|
||||||
LastUsedAt *time.Time
|
SignupSource string
|
||||||
CreatedAt time.Time
|
LastLoginAt *time.Time
|
||||||
UpdatedAt time.Time
|
LastActiveAt *time.Time
|
||||||
|
LastUsedAt *time.Time
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
|
||||||
// GroupRates 用户专属分组倍率配置
|
// GroupRates 用户专属分组倍率配置
|
||||||
// map[groupID]rateMultiplier
|
// map[groupID]rateMultiplier
|
||||||
|
|||||||
@@ -943,10 +943,11 @@ func (s *UserService) GetByID(ctx context.Context, id int64) (*User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func normalizeLoadedUserTokenVersion(user *User) {
|
func normalizeLoadedUserTokenVersion(user *User) {
|
||||||
if user == nil {
|
if user == nil || user.TokenVersionResolved {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
user.TokenVersion = resolvedTokenVersion(user)
|
user.TokenVersion = resolvedTokenVersion(user)
|
||||||
|
user.TokenVersionResolved = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// TouchLastActive 通过防抖更新 users.last_active_at,减少鉴权热路径写放大。
|
// TouchLastActive 通过防抖更新 users.last_active_at,减少鉴权热路径写放大。
|
||||||
|
|||||||
Reference in New Issue
Block a user