feat: backend core - auth, user, role, permission, device, webhook, monitoring, cache, repository, service, middleware, API handlers
This commit is contained in:
116
internal/service/auth_admin_bootstrap.go
Normal file
116
internal/service/auth_admin_bootstrap.go
Normal file
@@ -0,0 +1,116 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user