Files
user-system/internal/service/auth_admin_bootstrap.go

117 lines
3.0 KiB
Go
Raw Normal View History

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)
}