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);
}
}