using System.ComponentModel.DataAnnotations; using System.Security.Claims; using Jiaowu.Api.Domain.Identity; using Jiaowu.Api.Infrastructure.Auth; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; namespace Jiaowu.Api.Controllers; [ApiController] [Route("api/auth")] public sealed class AuthController( UserManager userManager, ITokenService tokenService) : ControllerBase { [AllowAnonymous] [HttpPost("login")] public async Task> Login(LoginRequest request) { var user = await userManager.FindByNameAsync(request.UserName); if (user is null || !user.IsEnabled) { return Unauthorized(new ProblemDetails { Title = "登录失败", Detail = "账号或密码不正确,或账号已停用。", Status = StatusCodes.Status401Unauthorized }); } if (await userManager.IsLockedOutAsync(user) || !await userManager.CheckPasswordAsync(user, request.Password)) { await userManager.AccessFailedAsync(user); return Unauthorized(new ProblemDetails { Title = "登录失败", Detail = "账号或密码不正确,或账号已停用。", Status = StatusCodes.Status401Unauthorized }); } await userManager.ResetAccessFailedCountAsync(user); user.LastLoginAt = DateTime.UtcNow; await userManager.UpdateAsync(user); var roles = await userManager.GetRolesAsync(user); return new LoginResponse( tokenService.Create(user, roles), new CurrentUserResponse( user.Id, user.UserName!, user.DisplayName, roles, user.CollegeId, EffectiveDataScopeResolver.Resolve(roles).ToString())); } [Authorize] [HttpGet("me")] public async Task> Me() { var id = User.FindFirstValue(ClaimTypes.NameIdentifier); var user = id is null ? null : await userManager.FindByIdAsync(id); if (user is null || !user.IsEnabled) { return Unauthorized(); } var roles = await userManager.GetRolesAsync(user); return new CurrentUserResponse( user.Id, user.UserName!, user.DisplayName, roles, user.CollegeId, EffectiveDataScopeResolver.Resolve(roles).ToString()); } } public sealed record LoginRequest( [Required, MaxLength(100)] string UserName, [Required, MaxLength(100)] string Password); public sealed record LoginResponse(string Token, CurrentUserResponse User); public sealed record CurrentUserResponse( Guid Id, string UserName, string DisplayName, IEnumerable Roles, Guid? CollegeId, string EffectiveDataScope);