Convert Auth module to MediatR command
Adds the MediatR package and wires AddMediatR in DI. Replaces IAuthService/AuthService with LoginCommand/LoginHandler, the pattern the remaining modules will follow.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Mws.Application.Auth;
|
using Mws.Application.Auth;
|
||||||
@@ -7,12 +8,12 @@ namespace Mws.Api.Controllers;
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/auth")]
|
[Route("api/auth")]
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
public class AuthController(IAuthService authService) : ControllerBase
|
public class AuthController(ISender sender) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpPost("login")]
|
[HttpPost("login")]
|
||||||
public async Task<ActionResult<LoginResponse>> Login([FromBody] LoginRequest request, CancellationToken ct)
|
public async Task<ActionResult<LoginResponse>> Login([FromBody] LoginRequest request, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var response = await authService.LoginAsync(request, ct);
|
var response = await sender.Send(new LoginCommand(request), ct);
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using Mws.Application.Common;
|
|
||||||
|
|
||||||
namespace Mws.Application.Auth;
|
|
||||||
|
|
||||||
public interface IAuthService
|
|
||||||
{
|
|
||||||
Task<LoginResponse> LoginAsync(LoginRequest request, CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AuthService(IUnitOfWork uow, IPasswordHasher passwordHasher, ITokenService tokenService, IMapper mapper)
|
|
||||||
: IAuthService
|
|
||||||
{
|
|
||||||
public async Task<LoginResponse> LoginAsync(LoginRequest request, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var username = request.Username.Trim();
|
|
||||||
var user = await uow.Users.GetByUsernameWithRoleAsync(username, cancellationToken);
|
|
||||||
|
|
||||||
if (user is null || !passwordHasher.Verify(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<UserDto>(user),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using MediatR;
|
||||||
|
using Mws.Application.Common;
|
||||||
|
|
||||||
|
namespace Mws.Application.Auth;
|
||||||
|
|
||||||
|
public record LoginCommand(LoginRequest Request) : IRequest<LoginResponse>;
|
||||||
|
|
||||||
|
public class LoginHandler(IUnitOfWork uow, IPasswordHasher passwordHasher, ITokenService tokenService, IMapper mapper)
|
||||||
|
: IRequestHandler<LoginCommand, LoginResponse>
|
||||||
|
{
|
||||||
|
public async Task<LoginResponse> 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<UserDto>(user),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper" Version="16.2.0" />
|
<PackageReference Include="AutoMapper" Version="16.2.0" />
|
||||||
|
<PackageReference Include="MediatR" Version="14.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public static class DependencyInjection
|
|||||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||||
|
|
||||||
services.AddAutoMapper(cfg => { }, typeof(MappingProfile).Assembly);
|
services.AddAutoMapper(cfg => { }, typeof(MappingProfile).Assembly);
|
||||||
|
services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(IUnitOfWork).Assembly));
|
||||||
|
|
||||||
services.AddScoped<IPasswordHasher, BcryptPasswordHasher>();
|
services.AddScoped<IPasswordHasher, BcryptPasswordHasher>();
|
||||||
|
|
||||||
@@ -39,7 +40,6 @@ public static class DependencyInjection
|
|||||||
services.AddSingleton(jwtOptions);
|
services.AddSingleton(jwtOptions);
|
||||||
services.AddScoped<ITokenService, JwtTokenService>();
|
services.AddScoped<ITokenService, JwtTokenService>();
|
||||||
|
|
||||||
services.AddScoped<IAuthService, AuthService>();
|
|
||||||
services.AddScoped<IAccountService, AccountService>();
|
services.AddScoped<IAccountService, AccountService>();
|
||||||
services.AddScoped<IPermissionService, PermissionService>();
|
services.AddScoped<IPermissionService, PermissionService>();
|
||||||
services.AddScoped<IRoleService, RoleService>();
|
services.AddScoped<IRoleService, RoleService>();
|
||||||
|
|||||||
Reference in New Issue
Block a user