using AutoMapper; using MediatR; using mws.backend.dotnet.application.Common; using mws.backend.dotnet.application.Users; namespace mws.backend.dotnet.application.Auth; public record LoginCommand(LoginRequest Request) : IRequest; public class LoginHandler(IUnitOfWork uow, IPasswordHasher passwordHasher, ITokenService tokenService, IMapper mapper) : IRequestHandler { public async Task Handle(LoginCommand command, CancellationToken ct) { var username = command.Request.Username.Trim(); var user = await uow.Users.GetByUsernameWithRoleAsync(username, ct); if (user is null || !passwordHasher.Verify(command.Request.Password, user.PasswordHash)) { throw new UnauthorizedException("Invalid username or password"); } if (!user.IsActive) { throw new ForbiddenException("Account disabled"); } return new LoginResponse { Token = tokenService.CreateToken(user.Id, user.Username), User = mapper.Map(user), }; } }