using Fengling.Console.Models.Dtos; using Fengling.Platform.Domain.AggregatesModel.UserAggregate; using Fengling.Platform.Domain.AggregatesModel.RoleAggregate; using Fengling.Platform.Infrastructure; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using System.Security.Claims; namespace Fengling.Console.Services; public interface IRoleService { Task<(IEnumerable Items, int TotalCount)> GetRolesAsync(int page, int pageSize, string? name = null, string? tenantId = null); Task GetRoleAsync(long id); Task> GetRoleUsersAsync(long id); Task CreateRoleAsync(CreateRoleDto dto); Task UpdateRoleAsync(long id, UpdateRoleDto dto); Task DeleteRoleAsync(long id); Task AddUserToRoleAsync(long roleId, long userId); Task RemoveUserFromRoleAsync(long roleId, long userId); } public class RoleService : IRoleService { private readonly ITenantManager _tenantManager; private readonly UserManager _userManager; private readonly RoleManager _roleManager; private readonly PlatformDbContext _context; private readonly IHttpContextAccessor _httpContextAccessor; public RoleService( ITenantManager tenantManager, UserManager userManager, RoleManager roleManager, PlatformDbContext context, IHttpContextAccessor httpContextAccessor) { _tenantManager = tenantManager; _userManager = userManager; _roleManager = roleManager; _context = context; _httpContextAccessor = httpContextAccessor; } public async Task<(IEnumerable Items, int TotalCount)> GetRolesAsync(int page, int pageSize, string? name = null, string? tenantId = null) { var query = _context.Roles.AsQueryable(); if (!string.IsNullOrEmpty(name)) { query = query.Where(r => r.Name != null && r.Name.Contains(name)); } if (!string.IsNullOrEmpty(tenantId)) { query = query.Where(r => r.TenantId.HasValue && r.TenantId.Value.ToString().Contains(tenantId)); } var totalCount = await query.CountAsync(); var roles = await query .OrderByDescending(r => r.CreatedTime) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); var roleDtos = new List(); foreach (var role in roles) { var users = await _userManager.GetUsersInRoleAsync(role.Name!); roleDtos.Add(new RoleDto { Id = role.Id, Name = role.Name, DisplayName = role.DisplayName, Description = role.Description, TenantId = role.TenantId, IsSystem = role.IsSystem, Permissions = role.Permissions, UserCount = users.Count, CreatedAt = role.CreatedTime }); } return (roleDtos, totalCount); } public async Task GetRoleAsync(long id) { var role = await _context.Roles.FindAsync(id); if (role == null) return null; return new RoleDto { Id = role.Id, Name = role.Name, DisplayName = role.DisplayName, Description = role.Description, TenantId = role.TenantId, IsSystem = role.IsSystem, Permissions = role.Permissions, UserCount = (await _userManager.GetUsersInRoleAsync(role.Name!)).Count, CreatedAt = role.CreatedTime }; } public async Task> GetRoleUsersAsync(long id) { var role = await _context.Roles.FindAsync(id); if (role == null) { throw new KeyNotFoundException($"Role with ID {id} not found"); } var users = await _userManager.GetUsersInRoleAsync(role.Name!); var userDtos = new List(); foreach (var user in users) { var roles = await _userManager.GetRolesAsync(user); var tenant = user.TenantInfo?.TenantId > 0 ? await _tenantManager.FindByIdAsync(user.TenantInfo.TenantId) : null; userDtos.Add(new UserDto { Id = user.Id, UserName = user.UserName, Email = user.Email, RealName = user.RealName, TenantCode = user.TenantInfo?.TenantCode, TenantName = tenant?.Name ?? "", Roles = roles.ToList(), EmailConfirmed = user.EmailConfirmed, IsActive = !user.LockoutEnabled || user.LockoutEnd == null || user.LockoutEnd < DateTimeOffset.UtcNow, CreatedAt = user.CreatedTime }); } return userDtos; } public async Task CreateRoleAsync(CreateRoleDto dto) { var role = new ApplicationRole { Name = dto.Name, DisplayName = dto.DisplayName, Description = dto.Description, TenantId = dto.TenantId.HasValue ? dto.TenantId.Value : null, Permissions = dto.Permissions, IsSystem = false, CreatedTime = DateTime.UtcNow }; var result = await _roleManager.CreateAsync(role); if (!result.Succeeded) { throw new InvalidOperationException(string.Join(", ", result.Errors.Select(e => e.Description))); } await CreateAuditLog("role", "create", "Role", role.Id, role.DisplayName, null, System.Text.Json.JsonSerializer.Serialize(dto)); return new RoleDto { Id = role.Id, Name = role.Name, DisplayName = role.DisplayName, Description = role.Description, TenantId = role.TenantId, IsSystem = role.IsSystem, Permissions = role.Permissions, UserCount = 0, CreatedAt = role.CreatedTime }; } public async Task UpdateRoleAsync(long id, UpdateRoleDto dto) { var role = await _context.Roles.FindAsync(id); if (role == null) { throw new KeyNotFoundException($"Role with ID {id} not found"); } if (role.IsSystem) { throw new InvalidOperationException("系统角色不能修改"); } var oldValue = System.Text.Json.JsonSerializer.Serialize(role); role.DisplayName = dto.DisplayName; role.Description = dto.Description; role.Permissions = dto.Permissions; await _roleManager.UpdateAsync(role); await CreateAuditLog("role", "update", "Role", role.Id, role.DisplayName, oldValue, System.Text.Json.JsonSerializer.Serialize(role)); var users = await _userManager.GetUsersInRoleAsync(role.Name!); return new RoleDto { Id = role.Id, Name = role.Name, DisplayName = role.DisplayName, Description = role.Description, TenantId = role.TenantId, IsSystem = role.IsSystem, Permissions = role.Permissions, UserCount = users.Count, CreatedAt = role.CreatedTime }; } public async Task DeleteRoleAsync(long id) { var role = await _context.Roles.FindAsync(id); if (role == null) { throw new KeyNotFoundException($"Role with ID {id} not found"); } if (role.IsSystem) { throw new InvalidOperationException("系统角色不能删除"); } var oldValue = System.Text.Json.JsonSerializer.Serialize(role); var users = await _userManager.GetUsersInRoleAsync(role.Name!); foreach (var user in users) { await _userManager.RemoveFromRoleAsync(user, role.Name!); } await _roleManager.DeleteAsync(role); await CreateAuditLog("role", "delete", "Role", role.Id, role.DisplayName, oldValue); } public async Task AddUserToRoleAsync(long roleId, long userId) { var role = await _context.Roles.FindAsync(roleId); if (role == null) { throw new KeyNotFoundException($"Role with ID {roleId} not found"); } var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { throw new KeyNotFoundException($"User with ID {userId} not found"); } var result = await _userManager.AddToRoleAsync(user, role.Name!); if (!result.Succeeded) { throw new InvalidOperationException(string.Join(", ", result.Errors.Select(e => e.Description))); } await CreateAuditLog("role", "update", "UserRole", null, $"{role.Name} - {user.UserName}"); } public async Task RemoveUserFromRoleAsync(long roleId, long userId) { var role = await _context.Roles.FindAsync(roleId); if (role == null) { throw new KeyNotFoundException($"Role with ID {roleId} not found"); } var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { throw new KeyNotFoundException($"User with ID {userId} not found"); } var result = await _userManager.RemoveFromRoleAsync(user, role.Name!); if (!result.Succeeded) { throw new InvalidOperationException(string.Join(", ", result.Errors.Select(e => e.Description))); } await CreateAuditLog("role", "update", "UserRole", null, $"{role.Name} - {user.UserName}"); } private async Task CreateAuditLog(string operation, string action, string targetType, long? targetId, string? targetName, string? oldValue = null, string? newValue = null) { var httpContext = _httpContextAccessor.HttpContext; var userName = httpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier) ?? httpContext?.User?.Identity?.Name ?? "system"; var tenantId = httpContext?.User?.FindFirstValue("TenantId"); var log = new AuditLog { Operator = userName, TenantId = tenantId, Operation = operation, Action = action, TargetType = targetType, TargetId = targetId, TargetName = targetName, IpAddress = httpContext?.Connection?.RemoteIpAddress?.ToString() ?? "unknown", Status = "success", OldValue = oldValue, NewValue = newValue, CreatedAt = DateTime.UtcNow }; _context.AuditLogs.Add(log); await _context.SaveChangesAsync(); } }