diff --git a/internal/services/auth_service.go b/internal/services/auth_service.go index 64d2e23..7f35ba2 100644 --- a/internal/services/auth_service.go +++ b/internal/services/auth_service.go @@ -278,7 +278,7 @@ func (s *authService) resolveTokenTTL(authCfg config.AuthConfig) time.Duration { func (s *authService) validateSessionToken(token string) (*models.LoginSession, error) { if strings.TrimSpace(token) == "" { - return nil, errorsx.InvalidToken("token 不能为空") + return nil, errorsx.Unauthorized("未登录或登录已过期") } session := LoginSessionService.FindOne(sqls.NewCnd().Eq("token", token)) if session == nil { @@ -411,7 +411,7 @@ func (s *authService) createLoginCredentialLog(principal string, userID int64, s func (s *authService) isCredentialLocked(username string, authCfg config.AuthConfig) bool { maxFailedAttempts := authCfg.MaxFailedAttempts if maxFailedAttempts <= 0 { - maxFailedAttempts = 5 + return false } lockMinute := authCfg.CredentialLockMinute if lockMinute <= 0 { @@ -421,7 +421,6 @@ func (s *authService) isCredentialLocked(username string, authCfg config.AuthCon return LoginCredentialLogService.Count(sqls.NewCnd(). Eq("principal", username). Eq("success", false). - NotEq("reason", "credential locked"). Where("created_at >= ?", since)) >= int64(maxFailedAttempts) } diff --git a/internal/services/auth_service_test.go b/internal/services/auth_service_test.go index 3c250c5..4c85e49 100644 --- a/internal/services/auth_service_test.go +++ b/internal/services/auth_service_test.go @@ -155,11 +155,43 @@ func TestAuthServiceLoginCredentialLockout(t *testing.T) { } } +func TestAuthServiceCredentialLockoutDisabledWhenMaxAttemptsNonPositive(t *testing.T) { + db := setupAuthServiceTestDB(t) + user := createAuthTestUser(t, db, "admin", "secret") + now := time.Now() + for i := 0; i < 3; i++ { + if err := db.Create(&models.LoginCredentialLog{ + Principal: "admin", + UserID: user.ID, + Success: false, + Reason: "credential locked", + CreatedAt: now.Add(-time.Duration(i+1) * time.Minute), + }).Error; err != nil { + t.Fatalf("seed credential log: %v", err) + } + } + + ret, err := newAuthService().Login(request.LoginRequest{Username: "admin", Password: "secret"}, config.AuthConfig{ + TokenTTLHours: 2, + MaxFailedAttempts: 0, + CredentialLockMinute: 15, + }, "127.0.0.1", "go-test") + if err != nil { + t.Fatalf("expected lockout to be disabled, got %v", err) + } + if ret == nil || ret.AccessToken == "" { + t.Fatalf("expected login response with access token, got %+v", ret) + } +} + func TestValidateSessionTokenStates(t *testing.T) { db := setupAuthServiceTestDB(t) svc := newAuthService() now := time.Now() + if _, err := svc.validateSessionToken(" "); !hasCode(err, errorsx.CodeAuthUnauthorized) { + t.Fatalf("expected unauthorized for empty token, got %v", err) + } if _, err := svc.validateSessionToken("missing"); !hasCode(err, errorsx.CodeAuthInvalidToken) { t.Fatalf("expected invalid token for missing session, got %v", err) }