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

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