using Fengling.AuthService.Data; using Fengling.AuthService.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using System.Security.Claims; namespace Fengling.AuthService.Controllers; [ApiController] [Route("api/[controller]")] [Authorize] public class RolesController : ControllerBase { private readonly ApplicationDbContext _context; private readonly RoleManager _roleManager; private readonly UserManager _userManager; private readonly ILogger _logger; public RolesController( ApplicationDbContext context, RoleManager roleManager, UserManager userManager, ILogger logger) { _context = context; _roleManager = roleManager; _userManager = userManager; _logger = logger; } [HttpGet] public async Task> GetRoles( [FromQuery] int page = 1, [FromQuery] int pageSize = 10, [FromQuery] string? name = null, [FromQuery] 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.ToString() == tenantId); } var totalCount = await query.CountAsync(); var roles = await query .OrderByDescending(r => r.CreatedTime) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); var result = new List(); foreach (var role in roles) { var users = await _userManager.GetUsersInRoleAsync(role.Name!); result.Add(new { 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 Ok(new { items = result, totalCount, page, pageSize }); } [HttpGet("{id}")] public async Task> GetRole(long id) { var role = await _context.Roles.FindAsync(id); if (role == null) { return NotFound(); } return Ok(new { id = role.Id, name = role.Name, displayName = role.DisplayName, description = role.Description, tenantId = role.TenantId, isSystem = role.IsSystem, permissions = role.Permissions, createdAt = role.CreatedTime, }); } [HttpGet("{id}/users")] public async Task>> GetRoleUsers(long id) { var role = await _context.Roles.FindAsync(id); if (role == null) { return NotFound(); } var users = await _userManager.GetUsersInRoleAsync(role.Name!); var result = users.Select(async u => new { id = u.Id, userName = u.UserName, email = u.Email, realName = u.RealName, tenantId = u.TenantInfo.TenantId, roles = await _userManager.GetRolesAsync(u), isActive = !u.LockoutEnabled || u.LockoutEnd == null || u.LockoutEnd < DateTimeOffset.UtcNow, createdAt = u.CreatedTime, }); return Ok(await Task.WhenAll(result)); } [HttpPost] public async Task> CreateRole(CreateRoleDto dto) { var role = new ApplicationRole { Name = dto.Name, DisplayName = dto.DisplayName, Description = dto.Description, TenantId = dto.TenantId, Permissions = dto.Permissions, IsSystem = false, CreatedTime = DateTime.UtcNow, }; var result = await _roleManager.CreateAsync(role); if (!result.Succeeded) { return BadRequest(result.Errors); } await CreateAuditLog("role", "create", "Role", role.Id, role.DisplayName, null, SerializeToJson(dto)); return CreatedAtAction(nameof(GetRole), new { id = role.Id }, role); } [HttpPut("{id}")] public async Task UpdateRole(long id, UpdateRoleDto dto) { var role = await _context.Roles.FindAsync(id); if (role == null) { return NotFound(); } if (role.IsSystem) { return BadRequest("系统角色不能修改"); } var oldValue = System.Text.Json.JsonSerializer.Serialize(role); role.DisplayName = dto.DisplayName; role.Description = dto.Description; role.Permissions = dto.Permissions; await _context.SaveChangesAsync(); await CreateAuditLog("role", "update", "Role", role.Id, role.DisplayName, oldValue, System.Text.Json.JsonSerializer.Serialize(role)); return NoContent(); } [HttpDelete("{id}")] public async Task DeleteRole(long id) { var role = await _context.Roles.FindAsync(id); if (role == null) { return NotFound(); } if (role.IsSystem) { return BadRequest("系统角色不能删除"); } 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!); } _context.Roles.Remove(role); await _context.SaveChangesAsync(); await CreateAuditLog("role", "delete", "Role", role.Id, role.DisplayName, oldValue); return NoContent(); } [HttpDelete("{id}/users/{userId}")] public async Task RemoveUserFromRole(long id, long userId) { var role = await _context.Roles.FindAsync(id); if (role == null) { return NotFound(); } var user = await _userManager.FindByIdAsync(userId.ToString()); if (user == null) { return NotFound(); } var result = await _userManager.RemoveFromRoleAsync(user, role.Name!); if (!result.Succeeded) { return BadRequest(result.Errors); } await CreateAuditLog("role", "update", "UserRole", null, $"{role.Name} - {user.UserName}"); return NoContent(); } private async Task CreateAuditLog(string operation, string action, string targetType, long? targetId, string? targetName, string? oldValue = null, string? newValue = null) { var userName = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.Identity?.Name ?? "system"; var tenantId = 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, }; _context.AuditLogs.Add(log); await _context.SaveChangesAsync(); } private string SerializeToJson(object obj) { return System.Text.Json.JsonSerializer.Serialize(obj, new System.Text.Json.JsonSerializerOptions { WriteIndented = false }); } } public class CreateRoleDto { public string Name { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string? Description { get; set; } public long? TenantId { get; set; } public List Permissions { get; set; } = new(); } public class UpdateRoleDto { public string DisplayName { get; set; } = string.Empty; public string? Description { get; set; } public List Permissions { get; set; } = new(); }