using Fengling.Backend.Domain.AggregatesModel.AdminAggregate; using Fengling.Backend.Infrastructure.Repositories; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace Fengling.Backend.Web.Application.Commands.AdminAuth; /// /// 管理员登录命令 /// public record AdminLoginCommand(string Username, string Password) : ICommand; /// /// 管理员登录响应 /// public record AdminLoginResponse(AdminId AdminId, string Username, string Token, DateTime ExpiresAt); /// /// 管理员登录命令验证器 /// public class AdminLoginCommandValidator : AbstractValidator { public AdminLoginCommandValidator() { RuleFor(x => x.Username) .NotEmpty().WithMessage("用户名不能为空") .MaximumLength(50).WithMessage("用户名长度不能超过50个字符"); RuleFor(x => x.Password) .NotEmpty().WithMessage("密码不能为空"); } } /// /// 管理员登录命令处理器 /// public class AdminLoginCommandHandler( IAdminRepository adminRepository, IConfiguration configuration) : ICommandHandler { public async Task Handle(AdminLoginCommand command, CancellationToken cancellationToken) { // 1. 通过用户名查询管理员 var admin = await adminRepository.GetByUsernameAsync(command.Username, cancellationToken); if (admin is null) { throw new KnownException("用户名或密码错误"); } // 2. 检查状态 if (admin.Status == AdminStatus.Disabled) { throw new KnownException("账号已被禁用"); } // 3. 验证密码 if (!admin.VerifyPassword(command.Password)) { throw new KnownException("用户名或密码错误"); } // 4. 记录登录时间 admin.RecordLogin(); // 5. 生成 JWT Token var token = GenerateJwtToken(admin.Id, admin.Username); var expiresAt = DateTime.UtcNow.AddHours(24); return new AdminLoginResponse(admin.Id, admin.Username, token, expiresAt); } private string GenerateJwtToken(AdminId adminId, string username) { var appConfig = configuration.GetSection("AppConfiguration").Get() ?? new Utils.AppConfiguration { JwtIssuer = "FenglingBackend", JwtAudience = "FenglingBackend", Secret = "YourVerySecretKeyForJwtTokenGeneration12345!" }; var claims = new[] { new Claim(ClaimTypes.NameIdentifier, adminId.ToString()), new Claim(ClaimTypes.Name, username), new Claim(ClaimTypes.Role, "Admin"), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; // 使用对称密钥 var secret = appConfig.Secret.Length >= 32 ? appConfig.Secret : "YourVerySecretKeyForJwtTokenGeneration12345!"; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: appConfig.JwtIssuer, audience: appConfig.JwtAudience, claims: claims, expires: DateTime.UtcNow.AddHours(24), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); } }