1
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Security.Claims;
|
||||
using Jiaowu.Api.Domain.Identity;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Jiaowu.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize(Roles = SystemRoles.SuperAdmin)]
|
||||
[Route("api/users")]
|
||||
public sealed class UsersController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
RoleManager<ApplicationRole> roleManager) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<object>> GetUsers(CancellationToken cancellationToken)
|
||||
{
|
||||
var users = await userManager.Users.AsNoTracking()
|
||||
.OrderBy(x => x.UserName)
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id, x.UserName, x.DisplayName, x.StaffNumber,
|
||||
x.CollegeId, x.IsEnabled, x.LastLoginAt, x.CreatedAt
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var result = new List<object>();
|
||||
foreach (var user in users)
|
||||
{
|
||||
var identityUser = await userManager.FindByIdAsync(user.Id.ToString());
|
||||
result.Add(new
|
||||
{
|
||||
user.Id, user.UserName, user.DisplayName, user.StaffNumber,
|
||||
user.CollegeId, user.IsEnabled, user.LastLoginAt, user.CreatedAt,
|
||||
Roles = identityUser is null
|
||||
? []
|
||||
: await userManager.GetRolesAsync(identityUser)
|
||||
});
|
||||
}
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("roles")]
|
||||
public async Task<ActionResult<object>> GetRoles(CancellationToken cancellationToken) =>
|
||||
Ok(await roleManager.Roles.AsNoTracking()
|
||||
.OrderBy(x => x.Name)
|
||||
.Select(x => new { x.Name, x.Description, x.DataScope })
|
||||
.ToListAsync(cancellationToken));
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult> Create(CreateUserRequest request)
|
||||
{
|
||||
var invalidRoles = request.Roles
|
||||
.Except(SystemRoles.All, StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
if (invalidRoles.Length > 0)
|
||||
return ValidationProblem($"无效角色:{string.Join("、", invalidRoles)}");
|
||||
|
||||
var user = new ApplicationUser
|
||||
{
|
||||
UserName = request.UserName.Trim(),
|
||||
DisplayName = request.DisplayName.Trim(),
|
||||
StaffNumber = request.StaffNumber?.Trim(),
|
||||
CollegeId = request.CollegeId,
|
||||
LockoutEnabled = true,
|
||||
IsEnabled = true
|
||||
};
|
||||
var result = await userManager.CreateAsync(user, request.Password);
|
||||
if (!result.Succeeded)
|
||||
return IdentityValidationProblem(result);
|
||||
|
||||
result = await userManager.AddToRolesAsync(user, request.Roles);
|
||||
if (!result.Succeeded)
|
||||
return IdentityValidationProblem(result);
|
||||
|
||||
return CreatedAtAction(nameof(GetUsers), new { id = user.Id }, new { user.Id });
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}/status")]
|
||||
public async Task<IActionResult> SetStatus(Guid id, SetUserStatusRequest request)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(id.ToString());
|
||||
if (user is null) return NotFound();
|
||||
if (User.FindFirstValue(ClaimTypes.NameIdentifier) == id.ToString() &&
|
||||
!request.IsEnabled)
|
||||
return ValidationProblem("不能停用当前登录账号。");
|
||||
|
||||
user.IsEnabled = request.IsEnabled;
|
||||
var result = await userManager.UpdateAsync(user);
|
||||
return result.Succeeded ? NoContent() : IdentityValidationProblem(result);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}/roles")]
|
||||
public async Task<IActionResult> SetRoles(Guid id, SetRolesRequest request)
|
||||
{
|
||||
var user = await userManager.FindByIdAsync(id.ToString());
|
||||
if (user is null) return NotFound();
|
||||
|
||||
var invalidRoles = request.Roles
|
||||
.Except(SystemRoles.All, StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
if (invalidRoles.Length > 0)
|
||||
return ValidationProblem($"无效角色:{string.Join("、", invalidRoles)}");
|
||||
|
||||
var existing = await userManager.GetRolesAsync(user);
|
||||
if (User.FindFirstValue(ClaimTypes.NameIdentifier) == id.ToString() &&
|
||||
existing.Contains(SystemRoles.SuperAdmin) &&
|
||||
!request.Roles.Contains(SystemRoles.SuperAdmin))
|
||||
{
|
||||
return ValidationProblem("不能移除当前账号的超级管理员角色。");
|
||||
}
|
||||
|
||||
var removeResult = await userManager.RemoveFromRolesAsync(
|
||||
user,
|
||||
existing.Except(request.Roles));
|
||||
if (!removeResult.Succeeded) return IdentityValidationProblem(removeResult);
|
||||
var addResult = await userManager.AddToRolesAsync(
|
||||
user,
|
||||
request.Roles.Except(existing));
|
||||
return addResult.Succeeded ? NoContent() : IdentityValidationProblem(addResult);
|
||||
}
|
||||
|
||||
private ActionResult IdentityValidationProblem(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
ModelState.AddModelError(error.Code, error.Description);
|
||||
return ValidationProblem(ModelState);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record CreateUserRequest(
|
||||
[Required, MaxLength(50)] string UserName,
|
||||
[Required, MaxLength(50)] string DisplayName,
|
||||
[Required, MinLength(8), MaxLength(100)] string Password,
|
||||
[MaxLength(30)] string? StaffNumber,
|
||||
Guid? CollegeId,
|
||||
[MinLength(1)] string[] Roles);
|
||||
|
||||
public sealed record SetUserStatusRequest(bool IsEnabled);
|
||||
public sealed record SetRolesRequest([MinLength(1)] string[] Roles);
|
||||
Reference in New Issue
Block a user