using Fengling.Backend.Domain.AggregatesModel.MemberAggregate; using Fengling.Backend.Infrastructure.Repositories; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Fengling.Backend.Web.Utils; namespace Fengling.Backend.Web.Application.Commands.Members; /// /// 会员登录命令 /// public record LoginMemberCommand(string Phone, string Password) : ICommand; /// /// 登录响应 /// public record LoginMemberResponse(MemberId MemberId, string Token); /// /// 会员登录命令验证器 /// public class LoginMemberCommandValidator : AbstractValidator { public LoginMemberCommandValidator() { RuleFor(x => x.Phone) .NotEmpty().WithMessage("手机号不能为空"); RuleFor(x => x.Password) .NotEmpty().WithMessage("密码不能为空"); } } /// /// 会员登录命令处理器 /// public class LoginMemberCommandHandler( IMemberRepository memberRepository, IConfiguration configuration) : ICommandHandler { public async Task Handle(LoginMemberCommand command, CancellationToken cancellationToken) { // 查询会员 var member = await memberRepository.GetByPhoneAsync(command.Phone, cancellationToken) ?? throw new KnownException("手机号或密码错误"); // 验证密码 var hashedPassword = HashPassword(command.Password); if (member.Password != hashedPassword) throw new KnownException("手机号或密码错误"); // 检查状态 if (member.Status == MemberStatus.Disabled) throw new KnownException("该账号已被禁用"); // 生成JWT Token var token = GenerateJwtToken(member.Id, member.Phone); return new LoginMemberResponse(member.Id, token); } private static string HashPassword(string password) { return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(password)); } private string GenerateJwtToken(MemberId memberId, string phone) { var appConfig = configuration.GetSection("AppConfiguration").Get() ?? new AppConfiguration { JwtIssuer = "FenglingBackend", JwtAudience = "FenglingBackend", Secret = "YourVerySecretKeyForJwtTokenGeneration12345!", TokenExpiryInMinutes = 1440 // 24小时 }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes( appConfig.Secret.Length >= 32 ? appConfig.Secret : "YourVerySecretKeyForJwtTokenGeneration12345!")); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(ClaimTypes.NameIdentifier, memberId.ToString()), new Claim(ClaimTypes.Name, phone), new Claim(ClaimTypes.Role, "Member"), new Claim("member_id", memberId.ToString()) }; var token = new JwtSecurityToken( issuer: appConfig.JwtIssuer, audience: appConfig.JwtAudience, claims: claims, expires: DateTime.UtcNow.AddMinutes(appConfig.TokenExpiryInMinutes), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token); } }