package service import ( "context" "errors" "strings" "github.com/user-management-system/internal/auth" "github.com/user-management-system/internal/domain" ) var ErrAdminBootstrapUnavailable = errors.New("管理员初始化入口已关闭") type BootstrapAdminRequest struct { Username string `json:"username" binding:"required"` Password string `json:"password" binding:"required"` Email string `json:"email"` Nickname string `json:"nickname"` } func (s *AuthService) BootstrapAdmin(ctx context.Context, req *BootstrapAdminRequest, ip string) (*LoginResponse, error) { if req == nil { return nil, errors.New("管理员初始化请求不能为空") } if s == nil || s.userRepo == nil || s.userRoleRepo == nil || s.roleRepo == nil || s.jwtManager == nil { return nil, errors.New("管理员初始化能力未正确配置") } if !s.IsAdminBootstrapRequired(ctx) { return nil, ErrAdminBootstrapUnavailable } username := strings.TrimSpace(req.Username) email := strings.TrimSpace(req.Email) nickname := strings.TrimSpace(req.Nickname) if username == "" { return nil, errors.New("用户名不能为空") } if strings.TrimSpace(req.Password) == "" { return nil, errors.New("密码不能为空") } if err := s.validatePassword(req.Password); err != nil { return nil, err } exists, err := s.userRepo.ExistsByUsername(ctx, username) if err != nil { return nil, err } if exists { return nil, errors.New("用户名已存在") } if email != "" { exists, err = s.userRepo.ExistsByEmail(ctx, email) if err != nil { return nil, err } if exists { return nil, errors.New("邮箱已存在") } } adminRole, err := s.roleRepo.GetByCode(ctx, adminRoleCode) if err != nil { return nil, err } if adminRole == nil || adminRole.Status != domain.RoleStatusEnabled { return nil, errors.New("管理员角色不可用") } passwordHash, err := auth.HashPassword(req.Password) if err != nil { return nil, err } if nickname == "" { nickname = username } user := &domain.User{ Username: username, Email: domain.StrPtr(email), Password: passwordHash, Nickname: nickname, Status: domain.UserStatusActive, } if err := s.userRepo.Create(ctx, user); err != nil { return nil, err } if err := s.userRoleRepo.BatchCreate(ctx, []*domain.UserRole{ {UserID: user.ID, RoleID: adminRole.ID}, }); err != nil { _ = s.userRepo.Delete(ctx, user.ID) return nil, err } s.bestEffortUpdateLastLogin(ctx, user.ID, ip, "admin_bootstrap") s.cacheUserInfo(ctx, user) s.writeLoginLog(ctx, &user.ID, domain.LoginTypePassword, ip, true, "") s.publishEvent(ctx, domain.EventUserRegistered, map[string]interface{}{ "user_id": user.ID, "username": user.Username, "role": adminRoleCode, "source": "admin_bootstrap", }) s.publishEvent(ctx, domain.EventUserLogin, map[string]interface{}{ "user_id": user.ID, "username": user.Username, "ip": ip, "method": "admin_bootstrap", }) return s.generateLoginResponseWithoutRemember(ctx, user) }