243 lines
7.4 KiB
C#
243 lines
7.4 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using LingAdmin.IdentityService.Data;
|
|
using LingAdmin.IdentityService.Services;
|
|
using LingAdmin.Shared.DTOs;
|
|
|
|
namespace LingAdmin.IdentityService.Controllers;
|
|
|
|
/// <summary>
|
|
/// 用户管理控制器 - 管理员操作
|
|
/// </summary>
|
|
[ApiController]
|
|
[Route("api/[controller]")]
|
|
[Authorize(Roles = "Admin,SuperAdmin")]
|
|
public class UsersController : ControllerBase
|
|
{
|
|
private readonly IdentityDbContext _context;
|
|
private readonly IPasswordHasher _passwordHasher;
|
|
private readonly ILogger<UsersController> _logger;
|
|
|
|
public UsersController(
|
|
IdentityDbContext context,
|
|
IPasswordHasher passwordHasher,
|
|
ILogger<UsersController> logger)
|
|
{
|
|
_context = context;
|
|
_passwordHasher = passwordHasher;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取用户列表(分页)
|
|
/// </summary>
|
|
[HttpGet]
|
|
public async Task<ActionResult<ApiResponse<PaginatedResponse<UserDto>>>> GetUsers(
|
|
[FromQuery] PaginationRequest pagination)
|
|
{
|
|
var query = _context.Users.AsQueryable();
|
|
|
|
// Search
|
|
if (!string.IsNullOrWhiteSpace(pagination.Search))
|
|
{
|
|
var search = pagination.Search.ToLower();
|
|
query = query.Where(u =>
|
|
u.Name.ToLower().Contains(search) ||
|
|
u.Email.ToLower().Contains(search));
|
|
}
|
|
|
|
// Sort
|
|
query = pagination.SortBy?.ToLower() switch
|
|
{
|
|
"name" => pagination.SortDescending ? query.OrderByDescending(u => u.Name) : query.OrderBy(u => u.Name),
|
|
"email" => pagination.SortDescending ? query.OrderByDescending(u => u.Email) : query.OrderBy(u => u.Email),
|
|
"createdat" => pagination.SortDescending ? query.OrderByDescending(u => u.CreatedAt) : query.OrderBy(u => u.CreatedAt),
|
|
_ => query.OrderByDescending(u => u.CreatedAt)
|
|
};
|
|
|
|
var totalCount = await query.CountAsync();
|
|
|
|
var users = await query
|
|
.Skip((pagination.Page - 1) * pagination.PageSize)
|
|
.Take(pagination.PageSize)
|
|
.Select(u => new UserDto
|
|
{
|
|
Id = u.Id,
|
|
Name = u.Name,
|
|
Email = u.Email,
|
|
Status = u.Status,
|
|
CreatedAt = u.CreatedAt,
|
|
LastLoginAt = u.LastLoginAt
|
|
})
|
|
.ToListAsync();
|
|
|
|
var response = new PaginatedResponse<UserDto>
|
|
{
|
|
Items = users,
|
|
TotalCount = totalCount,
|
|
Page = pagination.Page,
|
|
PageSize = pagination.PageSize
|
|
};
|
|
|
|
return Ok(ApiResponse<PaginatedResponse<UserDto>>.Ok(response));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取单个用户
|
|
/// </summary>
|
|
[HttpGet("{id}")]
|
|
public async Task<ActionResult<ApiResponse<UserDto>>> GetUser(int id)
|
|
{
|
|
var user = await _context.Users.FindAsync(id);
|
|
|
|
if (user == null)
|
|
{
|
|
return NotFound(ApiResponse<UserDto>.NotFound("User not found"));
|
|
}
|
|
|
|
var userDto = new UserDto
|
|
{
|
|
Id = user.Id,
|
|
Name = user.Name,
|
|
Email = user.Email,
|
|
Status = user.Status,
|
|
CreatedAt = user.CreatedAt,
|
|
LastLoginAt = user.LastLoginAt
|
|
};
|
|
|
|
return Ok(ApiResponse<UserDto>.Ok(userDto));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新用户状态
|
|
/// </summary>
|
|
[HttpPatch("{id}/status")]
|
|
public async Task<ActionResult<ApiResponse<UserDto>>> UpdateUserStatus(int id, [FromBody] UpdateStatusRequest request)
|
|
{
|
|
var user = await _context.Users.FindAsync(id);
|
|
|
|
if (user == null)
|
|
{
|
|
return NotFound(ApiResponse<UserDto>.NotFound("User not found"));
|
|
}
|
|
|
|
if (!new[] { "Active", "Inactive", "Suspended" }.Contains(request.Status))
|
|
{
|
|
return BadRequest(ApiResponse<UserDto>.Error("Invalid status. Must be Active, Inactive, or Suspended"));
|
|
}
|
|
|
|
user.Status = request.Status;
|
|
user.UpdatedAt = DateTime.UtcNow;
|
|
await _context.SaveChangesAsync();
|
|
|
|
var userDto = new UserDto
|
|
{
|
|
Id = user.Id,
|
|
Name = user.Name,
|
|
Email = user.Email,
|
|
Status = user.Status,
|
|
CreatedAt = user.CreatedAt,
|
|
LastLoginAt = user.LastLoginAt
|
|
};
|
|
|
|
return Ok(ApiResponse<UserDto>.Ok(userDto, "User status updated"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重置用户密码(管理员操作)
|
|
/// </summary>
|
|
[HttpPost("{id}/reset-password")]
|
|
public async Task<ActionResult<ApiResponse<object>>> ResetUserPassword(int id, [FromBody] AdminResetPasswordRequest request)
|
|
{
|
|
var user = await _context.Users.FindAsync(id);
|
|
|
|
if (user == null)
|
|
{
|
|
return NotFound(ApiResponse<object>.NotFound("User not found"));
|
|
}
|
|
|
|
user.PasswordHash = _passwordHasher.HashPassword(request.NewPassword);
|
|
user.UpdatedAt = DateTime.UtcNow;
|
|
|
|
// Revoke all refresh tokens
|
|
var tokens = await _context.RefreshTokens
|
|
.Where(rt => rt.UserId == id && rt.RevokedAt == null)
|
|
.ToListAsync();
|
|
|
|
foreach (var token in tokens)
|
|
{
|
|
token.RevokedAt = DateTime.UtcNow;
|
|
}
|
|
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInformation("Admin reset password for user {UserId}", id);
|
|
|
|
return Ok(ApiResponse<object>.Ok(new { }, "Password reset successfully"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除用户
|
|
/// </summary>
|
|
[HttpDelete("{id}")]
|
|
[Authorize(Roles = "SuperAdmin")]
|
|
public async Task<ActionResult<ApiResponse<object>>> DeleteUser(int id)
|
|
{
|
|
var user = await _context.Users.FindAsync(id);
|
|
|
|
if (user == null)
|
|
{
|
|
return NotFound(ApiResponse<object>.NotFound("User not found"));
|
|
}
|
|
|
|
// Delete all refresh tokens
|
|
var tokens = await _context.RefreshTokens.Where(rt => rt.UserId == id).ToListAsync();
|
|
_context.RefreshTokens.RemoveRange(tokens);
|
|
|
|
_context.Users.Remove(user);
|
|
await _context.SaveChangesAsync();
|
|
|
|
_logger.LogInformation("User {UserId} deleted", id);
|
|
|
|
return Ok(ApiResponse<object>.Ok(new { }, "User deleted successfully"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// [开发用] 重置用户密码 - 仅在开发环境可用
|
|
/// </summary>
|
|
[HttpPost("{id}/dev-reset-password")]
|
|
[AllowAnonymous]
|
|
public async Task<ActionResult<ApiResponse<object>>> DevResetPassword(int id, [FromBody] AdminResetPasswordRequest request)
|
|
{
|
|
// Only allow in development
|
|
var env = HttpContext.RequestServices.GetService<IWebHostEnvironment>();
|
|
if (!env!.IsDevelopment())
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
var user = await _context.Users.FindAsync(id);
|
|
if (user == null)
|
|
{
|
|
return NotFound(ApiResponse<object>.NotFound("User not found"));
|
|
}
|
|
|
|
user.PasswordHash = _passwordHasher.HashPassword(request.NewPassword);
|
|
user.UpdatedAt = DateTime.UtcNow;
|
|
await _context.SaveChangesAsync();
|
|
|
|
return Ok(ApiResponse<object>.Ok(new { hash = user.PasswordHash }, "Password reset successfully"));
|
|
}
|
|
}
|
|
|
|
public class UpdateStatusRequest
|
|
{
|
|
public required string Status { get; set; }
|
|
}
|
|
|
|
public class AdminResetPasswordRequest
|
|
{
|
|
public required string NewPassword { get; set; }
|
|
}
|