117 lines
3.0 KiB
Go
117 lines
3.0 KiB
Go
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)
|
|
}
|