fix: v6 code review P0 auth/IDOR fixes + frontend regression patches
Backend fixes: - auth_handler: P0 认证逻辑修复 - ratelimit: 限速中间件增强 + 新增单元测试 - auth_service: 认证服务逻辑完善 + 新增测试 - server: server 配置增强 + 新增测试 - handler_test: 新增 handler 层集成测试 - auth_bootstrap_test: bootstrap 路径测试 Frontend patches: - LoginPage/RegisterPage: CSRF + 表单交互修复 - BootstrapAdminPage: 引导流程修复 - DevicesPage: 设备管理页修复 - auth/social-accounts/users/webhooks services: 类型修正 - csrf.ts: CSRF token 处理修正 - E2E 脚本: CDP smoke + auth e2e 增强 Docs: - FULL_CODE_REVIEW_REPORT_2026-04-20 - report-v6 执行计划 - REAL_PROJECT_STATUS 更新 - .gitignore: 新增 .gocache-*/config.yaml 排除 验证: go build/vet 0错误, go test 42/42 PASS, 0 FAIL
This commit is contained in:
@@ -3,10 +3,12 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/user-management-system/internal/auth"
|
||||
"github.com/user-management-system/internal/cache"
|
||||
"github.com/user-management-system/internal/domain"
|
||||
"github.com/user-management-system/internal/repository"
|
||||
"github.com/user-management-system/internal/security"
|
||||
@@ -359,6 +361,73 @@ func TestBuildDeviceFingerprint(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogin_IssuesTOTPChallengeTokenWhenSecondFactorIsRequired(t *testing.T) {
|
||||
db, err := gorm.Open(gormsqlite.New(gormsqlite.Config{
|
||||
DriverName: "sqlite",
|
||||
DSN: fmt.Sprintf("file:login_totp_challenge_%d?mode=memory&cache=shared", time.Now().UnixNano()),
|
||||
}), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to connect database: %v", err)
|
||||
}
|
||||
|
||||
if err := db.AutoMigrate(&domain.User{}); err != nil {
|
||||
t.Fatalf("failed to migrate: %v", err)
|
||||
}
|
||||
|
||||
jwtManager, err := auth.NewJWTWithOptions(auth.JWTOptions{
|
||||
HS256Secret: "totp-challenge-secret",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create jwt manager: %v", err)
|
||||
}
|
||||
|
||||
cacheManager := cache.NewCacheManager(cache.NewL1Cache(), cache.NewRedisCache(false))
|
||||
userRepo := repository.NewUserRepository(db)
|
||||
svc := NewAuthService(userRepo, nil, jwtManager, cacheManager, 8, 5, 15*time.Minute)
|
||||
|
||||
hashedPassword, err := auth.HashPassword("Password123!")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to hash password: %v", err)
|
||||
}
|
||||
|
||||
user := &domain.User{
|
||||
Username: "totpchallenge",
|
||||
Password: hashedPassword,
|
||||
Status: domain.UserStatusActive,
|
||||
TOTPEnabled: true,
|
||||
TOTPSecret: "JBSWY3DPEHPK3PXP",
|
||||
}
|
||||
if err := db.Create(user).Error; err != nil {
|
||||
t.Fatalf("failed to create user: %v", err)
|
||||
}
|
||||
|
||||
resp, err := svc.Login(context.Background(), &LoginRequest{
|
||||
Account: "totpchallenge",
|
||||
Password: "Password123!",
|
||||
DeviceID: "device-1",
|
||||
}, "127.0.0.1")
|
||||
if err != nil {
|
||||
t.Fatalf("login failed: %v", err)
|
||||
}
|
||||
|
||||
if !resp.RequiresTOTP {
|
||||
t.Fatalf("expected requires_totp response, got %+v", resp)
|
||||
}
|
||||
if resp.UserID != user.ID {
|
||||
t.Fatalf("expected user id %d, got %d", user.ID, resp.UserID)
|
||||
}
|
||||
if strings.TrimSpace(resp.TempToken) == "" {
|
||||
t.Fatalf("expected temp token when TOTP is required, got %+v", resp)
|
||||
}
|
||||
if resp.AccessToken != "" || resp.RefreshToken != "" {
|
||||
t.Fatalf("expected no full session tokens before TOTP verification, got %+v", resp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthServiceDefaultConfig(t *testing.T) {
|
||||
// Test that default configuration is applied correctly
|
||||
svc := NewAuthService(nil, nil, nil, nil, 0, 0, 0)
|
||||
|
||||
Reference in New Issue
Block a user