You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
7.1 KiB
205 lines
7.1 KiB
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.Extensions.Logging;
|
|
using X1.Domain.Entities;
|
|
using X1.Domain.Services;
|
|
using X1.Domain.ValueObjects;
|
|
using X1.Domain.Exceptions;
|
|
using System.Threading.Tasks;
|
|
using System.Linq;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using X1.Domain.Repositories;
|
|
using System.Threading;
|
|
using X1.Domain.Repositories.Identity;
|
|
using X1.Domain.Common;
|
|
|
|
namespace X1.Infrastructure.Services.UserManagement;
|
|
|
|
/// <summary>
|
|
/// 用户注册领域服务实现
|
|
/// </summary>
|
|
public class UserRegistrationService : IUserRegistrationService
|
|
{
|
|
private readonly UserManager<AppUser> _userManager;
|
|
private readonly RoleManager<AppRole> _roleManager;
|
|
private readonly ILogger<UserRegistrationService> _logger;
|
|
private readonly IDistributedLockService _lockService;
|
|
private readonly IUserRoleRepository _userRoleRepository;
|
|
private const string Description = "超级管理员";
|
|
public UserRegistrationService(
|
|
UserManager<AppUser> userManager,
|
|
RoleManager<AppRole> roleManager,
|
|
ILogger<UserRegistrationService> logger,
|
|
IUserRoleRepository userRoleRepository,
|
|
IDistributedLockService lockService)
|
|
{
|
|
_userManager = userManager;
|
|
_roleManager = roleManager;
|
|
_logger = logger;
|
|
_lockService = lockService;
|
|
_userRoleRepository = userRoleRepository;
|
|
}
|
|
|
|
public async Task<(bool success, string? errorMessage)> RegisterUserAsync(AppUser user, string password)
|
|
{
|
|
// 验证账号
|
|
var userNameResult = UserName.Create(user.UserName ?? string.Empty);
|
|
if (userNameResult.IsFailure)
|
|
{
|
|
throw new UserRegistrationException(userNameResult.Error!);
|
|
}
|
|
|
|
// 验证用户名
|
|
if (string.IsNullOrWhiteSpace(user.RealName))
|
|
{
|
|
throw new UserRegistrationException("用户名不能为空");
|
|
}
|
|
|
|
if (user.RealName.Length > 50)
|
|
{
|
|
throw new UserRegistrationException("用户名长度不能超过50个字符");
|
|
}
|
|
|
|
// 验证邮箱
|
|
var emailResult = Email.Create(user.Email ?? string.Empty);
|
|
if (emailResult.IsFailure)
|
|
{
|
|
throw new UserRegistrationException(emailResult.Error!);
|
|
}
|
|
|
|
// 使用分布式锁确保用户名和邮箱的唯一性
|
|
using var lockHandle = await _lockService.AcquireLockAsync($"user_registration_{user.UserName ?? "unknown"}", TimeSpan.FromSeconds(10));
|
|
if (!lockHandle.IsAcquired)
|
|
{
|
|
throw new UserRegistrationException("系统繁忙,请稍后重试");
|
|
}
|
|
|
|
// 检查账号是否存在
|
|
var existingUser = await _userManager.FindByNameAsync(user.UserName ?? string.Empty);
|
|
if (existingUser != null)
|
|
{
|
|
throw new UserNameAlreadyExistsException(user.UserName ?? string.Empty);
|
|
}
|
|
|
|
// 检查邮箱是否存在
|
|
existingUser = await _userManager.FindByEmailAsync(user.Email ?? string.Empty);
|
|
if (existingUser != null)
|
|
{
|
|
throw new EmailAlreadyExistsException(user.Email ?? string.Empty);
|
|
}
|
|
|
|
// 创建用户
|
|
var result = await _userManager.CreateAsync(user, password);
|
|
if (!result.Succeeded)
|
|
{
|
|
var errors = result.Errors.Select(e => e.Description);
|
|
throw new UserRegistrationException(string.Join(", ", errors));
|
|
}
|
|
|
|
return (true, null);
|
|
}
|
|
|
|
public async Task<(bool success, string? errorMessage)> AssignUserRoleAsync(AppUser user)
|
|
{
|
|
// 使用分布式锁确保只有一个用户能被分配为Admin角色
|
|
using var lockHandle = await _lockService.AcquireLockAsync("first_user_role_assignment", TimeSpan.FromSeconds(10));
|
|
if (!lockHandle.IsAcquired)
|
|
{
|
|
throw new RoleAssignmentException("系统繁忙,请稍后重试");
|
|
}
|
|
|
|
// 检查是否是第一个用户
|
|
var isFirstUser = !await _userManager.Users.AnyAsync();
|
|
string roleName = isFirstUser ? RoleConstants.User : RoleConstants.Admin;
|
|
|
|
// 获取或创建角色
|
|
var role = await _roleManager.FindByNameAsync(roleName);
|
|
if (role == null)
|
|
{
|
|
role = new AppRole { Name = roleName,Description=(isFirstUser?string.Empty: Description) };
|
|
var roleResult = await _roleManager.CreateAsync(role);
|
|
if (!roleResult.Succeeded)
|
|
{
|
|
var errors = roleResult.Errors.Select(e => e.Description);
|
|
throw new RoleAssignmentException(string.Join(", ", errors));
|
|
}
|
|
}
|
|
|
|
// 创建用户角色关系
|
|
var userRole = new UserRole
|
|
{
|
|
UserId = user.Id,
|
|
RoleId = role.Id,
|
|
User = user
|
|
};
|
|
|
|
//分配角色
|
|
var result = await _userRoleRepository.AddAsync(userRole);
|
|
if (isFirstUser)
|
|
{
|
|
_logger.LogInformation("创建了第一个用户 {UserName},已分配管理员角色", user.UserName ?? "unknown");
|
|
}
|
|
|
|
return (true, null);
|
|
}
|
|
|
|
public async Task<(bool success, string? errorMessage)> AssignUserRolesAsync(AppUser user, string[] roleId)
|
|
{
|
|
if (roleId == null || roleId.Length == 0)
|
|
{
|
|
throw new RoleAssignmentException("角色ID数组不能为空");
|
|
}
|
|
|
|
// 使用分布式锁确保角色分配的原子性
|
|
using var lockHandle = await _lockService.AcquireLockAsync($"role_assignment_{user.Id}", TimeSpan.FromSeconds(10));
|
|
if (!lockHandle.IsAcquired)
|
|
{
|
|
throw new RoleAssignmentException("系统繁忙,请稍后重试");
|
|
}
|
|
|
|
var userRoles = new List<UserRole>();
|
|
var assignedRoles = new List<string>();
|
|
|
|
foreach (var roleIdItem in roleId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(roleIdItem))
|
|
{
|
|
throw new RoleAssignmentException("角色ID不能为空");
|
|
}
|
|
|
|
// 获取指定角色(管理员分配的角色一定存在)
|
|
var role = await _roleManager.FindByIdAsync(roleIdItem);
|
|
if (role == null)
|
|
{
|
|
throw new RoleAssignmentException($"角色ID {roleIdItem} 不存在");
|
|
}
|
|
|
|
// 检查用户是否已经有该角色
|
|
var hasRole = await _userRoleRepository.HasRoleAsync(user.Id, role.Id);
|
|
if (hasRole)
|
|
{
|
|
_logger.LogInformation("用户 {UserName} 已经拥有角色 {RoleName}", user.UserName ?? "unknown", role.Name);
|
|
continue;
|
|
}
|
|
|
|
// 创建用户角色关系
|
|
var userRole = new UserRole
|
|
{
|
|
UserId = user.Id,
|
|
RoleId = role.Id,
|
|
User = user
|
|
};
|
|
|
|
userRoles.Add(userRole);
|
|
assignedRoles.Add(role!.Name ?? string.Empty);
|
|
}
|
|
|
|
// 批量分配角色
|
|
if (userRoles.Count > 0)
|
|
{
|
|
await _userRoleRepository.AddUserRolesAsync(userRoles);
|
|
_logger.LogInformation("为用户 {UserName} 批量分配角色成功: {Roles}", user.UserName ?? "unknown", string.Join(", ", assignedRoles));
|
|
}
|
|
|
|
return (true, null);
|
|
}
|
|
}
|