diff --git a/src/Quizer.Api/Common/Mapping/AuthenticationMappingConfig.cs b/src/Quizer.Api/Common/Mapping/AuthenticationMappingConfig.cs index adc936b..9abc745 100644 --- a/src/Quizer.Api/Common/Mapping/AuthenticationMappingConfig.cs +++ b/src/Quizer.Api/Common/Mapping/AuthenticationMappingConfig.cs @@ -1,5 +1,6 @@ using Mapster; using Quizer.Application.Authentication.Commands.Login; +using Quizer.Application.Authentication.Commands.Logout; using Quizer.Application.Authentication.Commands.Register; using Quizer.Contracts.Authentication; @@ -18,5 +19,8 @@ public void Register(TypeAdapterConfig config) config.NewConfig() .Map(dest => dest, src => src.User); + + config.NewConfig() + .Map(dest => dest, src => src); } } diff --git a/src/Quizer.Api/Controllers/V1/AuthController.cs b/src/Quizer.Api/Controllers/V1/AuthController.cs index 8c58a97..c9e4fa2 100644 --- a/src/Quizer.Api/Controllers/V1/AuthController.cs +++ b/src/Quizer.Api/Controllers/V1/AuthController.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Quizer.Application.Authentication.Commands.Login; +using Quizer.Application.Authentication.Commands.Logout; using Quizer.Application.Authentication.Commands.RefreshToken; using Quizer.Application.Authentication.Commands.Register; using Quizer.Contracts.Authentication; @@ -62,6 +63,23 @@ public async Task Login(LoginRequest request) ); } + [HttpDelete("logout")] + public async Task Logout() + { + string? refreshToken = Request.Cookies["refreshToken"]; + if (refreshToken is null) + return Unauthorized(); + + var query = new LogoutCommand(refreshToken); + + var result = await _mediator.Send(query); + + return result.Match( + data => Ok(_mapper.Map(data)), + Problem + ); + } + [HttpPost("refresh")] public async Task RefreshToken() { diff --git a/src/Quizer.Application/Authentication/Commands/Logout/LogoutCommand.cs b/src/Quizer.Application/Authentication/Commands/Logout/LogoutCommand.cs new file mode 100644 index 0000000..43d1e2e --- /dev/null +++ b/src/Quizer.Application/Authentication/Commands/Logout/LogoutCommand.cs @@ -0,0 +1,8 @@ +using ErrorOr; +using MediatR; + +namespace Quizer.Application.Authentication.Commands.Logout; + +public record LogoutCommand( + string RefreshToken + ) : IRequest>; diff --git a/src/Quizer.Application/Authentication/Commands/Logout/LogoutCommandHandler.cs b/src/Quizer.Application/Authentication/Commands/Logout/LogoutCommandHandler.cs new file mode 100644 index 0000000..8dd909c --- /dev/null +++ b/src/Quizer.Application/Authentication/Commands/Logout/LogoutCommandHandler.cs @@ -0,0 +1,35 @@ +using ErrorOr; +using MediatR; +using Microsoft.AspNetCore.Identity; +using Quizer.Application.Common.Interfaces.Authentication; +using Quizer.Application.Common.Interfaces.Persistance; +using Quizer.Domain.Common.Errors; +using Quizer.Domain.RefreshTokenAggregate; +using Quizer.Domain.UserAggregate; + +namespace Quizer.Application.Authentication.Commands.Logout; + +public class LogoutCommandHandler : IRequestHandler> +{ + private readonly IRefreshTokenRepository _refreshTokenRepository; + private readonly SignInManager _signInManager; + + public LogoutCommandHandler(SignInManager signInManager, IRefreshTokenRepository refreshTokenRepository) + { + _signInManager = signInManager; + _refreshTokenRepository = refreshTokenRepository; + } + + public async Task> Handle(LogoutCommand query, CancellationToken cancellation) + { + var token = await _refreshTokenRepository.Get(TokenId.Create(query.RefreshToken)); + + if(token is null) + return Errors.Authentication.InvalidCredentials; + + _refreshTokenRepository.Delete(token); + await _signInManager.SignOutAsync(); + + return new LogoutResult(true); + } +} diff --git a/src/Quizer.Application/Authentication/Commands/Logout/LogoutResult.cs b/src/Quizer.Application/Authentication/Commands/Logout/LogoutResult.cs new file mode 100644 index 0000000..2221f68 --- /dev/null +++ b/src/Quizer.Application/Authentication/Commands/Logout/LogoutResult.cs @@ -0,0 +1,5 @@ +namespace Quizer.Application.Authentication.Commands.Logout; + +public record LogoutResult( + bool IsSuccess +); diff --git a/src/Quizer.Contracts/Authentication/LogoutResponse.cs b/src/Quizer.Contracts/Authentication/LogoutResponse.cs new file mode 100644 index 0000000..5a9f67b --- /dev/null +++ b/src/Quizer.Contracts/Authentication/LogoutResponse.cs @@ -0,0 +1,5 @@ +namespace Quizer.Contracts.Authentication; + +public record LogoutResponse( + bool IsSuccess +);