diff --git a/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommand.cs b/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommand.cs index 216eb8c..677be8e 100644 --- a/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommand.cs +++ b/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommand.cs @@ -1,6 +1,7 @@ using AipsCore.Application.Abstract.Command; using AipsCore.Application.Common.Authentication; +using AipsCore.Application.Common.Authentication.Dtos; namespace AipsCore.Application.Models.User.Command.LogIn; -public record LogInUserCommand(string Email, string Password) : ICommand; \ No newline at end of file +public record LogInUserCommand(string Email, string Password) : ICommand; \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommandHandler.cs b/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommandHandler.cs index eebaa7d..47abc89 100644 --- a/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommandHandler.cs +++ b/dotnet/AipsCore/Application/Models/User/Command/LogIn/LogInUserCommandHandler.cs @@ -1,28 +1,40 @@ using AipsCore.Application.Abstract.Command; using AipsCore.Application.Abstract.UserContext; using AipsCore.Application.Common.Authentication; +using AipsCore.Application.Common.Authentication.Dtos; using AipsCore.Domain.Abstract; -using AipsCore.Domain.Models.User.External; namespace AipsCore.Application.Models.User.Command.LogIn; -public class LogInUserCommandHandler : ICommandHandler +public class LogInUserCommandHandler : ICommandHandler { - private readonly IUserRepository _userRepository; private readonly ITokenProvider _tokenProvider; + private readonly IRefreshTokenRepository _refreshTokenRepository; private readonly IAuthService _authService; + private readonly IUnitOfWork _unitOfWork; - public LogInUserCommandHandler(IUserRepository userRepository, ITokenProvider tokenProvider, IAuthService authService) + public LogInUserCommandHandler( + ITokenProvider tokenProvider, + IRefreshTokenRepository refreshTokenRepository, + IAuthService authService, + IUnitOfWork unitOfWork) { - _userRepository = userRepository; _tokenProvider = tokenProvider; + _refreshTokenRepository = refreshTokenRepository; _authService = authService; + _unitOfWork = unitOfWork; } - public async Task Handle(LogInUserCommand command, CancellationToken cancellationToken = default) + public async Task Handle(LogInUserCommand command, CancellationToken cancellationToken = default) { var loginResult = await _authService.LoginWithEmailAndPasswordAsync(command.Email, command.Password, cancellationToken); - return new Token(_tokenProvider.Generate(loginResult.User, loginResult.Roles)); + var accessToken = _tokenProvider.GenerateAccessToken(loginResult.User, loginResult.Roles); + var refreshToken = _tokenProvider.GenerateRefreshToken(); + + await _refreshTokenRepository.AddAsync(refreshToken, loginResult.User.Id, cancellationToken); + await _unitOfWork.SaveChangesAsync(cancellationToken); + + return new LogInUserResultDto(accessToken, refreshToken); } } \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/LogOut/LogOutCommand.cs b/dotnet/AipsCore/Application/Models/User/Command/LogOut/LogOutCommand.cs new file mode 100644 index 0000000..4dba5f9 --- /dev/null +++ b/dotnet/AipsCore/Application/Models/User/Command/LogOut/LogOutCommand.cs @@ -0,0 +1,5 @@ +using AipsCore.Application.Abstract.Command; + +namespace AipsCore.Application.Models.User.Command.LogOut; + +public record LogOutCommand(string RefreshToken) : ICommand; \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/LogOut/LogOutCommandHandler.cs b/dotnet/AipsCore/Application/Models/User/Command/LogOut/LogOutCommandHandler.cs new file mode 100644 index 0000000..629fb55 --- /dev/null +++ b/dotnet/AipsCore/Application/Models/User/Command/LogOut/LogOutCommandHandler.cs @@ -0,0 +1,19 @@ +using AipsCore.Application.Abstract.Command; +using AipsCore.Application.Abstract.UserContext; + +namespace AipsCore.Application.Models.User.Command.LogOut; + +public class LogOutCommandHandler : ICommandHandler +{ + private readonly IRefreshTokenRepository _refreshTokenRepository; + + public LogOutCommandHandler(IRefreshTokenRepository refreshTokenRepository) + { + _refreshTokenRepository = refreshTokenRepository; + } + + public async Task Handle(LogOutCommand command, CancellationToken cancellationToken = default) + { + await _refreshTokenRepository.RevokeAsync(command.RefreshToken, cancellationToken); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/LogOutAll/LogOutAllCommand.cs b/dotnet/AipsCore/Application/Models/User/Command/LogOutAll/LogOutAllCommand.cs new file mode 100644 index 0000000..da0f25c --- /dev/null +++ b/dotnet/AipsCore/Application/Models/User/Command/LogOutAll/LogOutAllCommand.cs @@ -0,0 +1,5 @@ +using AipsCore.Application.Abstract.Command; + +namespace AipsCore.Application.Models.User.Command.LogOutAll; + +public record LogOutAllCommand : ICommand; \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/LogOutAll/LogOutAllCommandHandler.cs b/dotnet/AipsCore/Application/Models/User/Command/LogOutAll/LogOutAllCommandHandler.cs new file mode 100644 index 0000000..c324d76 --- /dev/null +++ b/dotnet/AipsCore/Application/Models/User/Command/LogOutAll/LogOutAllCommandHandler.cs @@ -0,0 +1,23 @@ +using AipsCore.Application.Abstract.Command; +using AipsCore.Application.Abstract.UserContext; + +namespace AipsCore.Application.Models.User.Command.LogOutAll; + +public class LogOutAllCommandHandler : ICommandHandler +{ + private readonly IRefreshTokenRepository _refreshTokenRepository; + private readonly IUserContext _userContext; + + public LogOutAllCommandHandler(IRefreshTokenRepository refreshTokenRepository, IUserContext userContext) + { + _refreshTokenRepository = refreshTokenRepository; + _userContext = userContext; + } + + public Task Handle(LogOutAllCommand command, CancellationToken cancellationToken = default) + { + var userId = _userContext.GetCurrentUserId(); + + return _refreshTokenRepository.RevokeAllAsync(userId, cancellationToken); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/RefreshLogIn/RefreshLogInCommand.cs b/dotnet/AipsCore/Application/Models/User/Command/RefreshLogIn/RefreshLogInCommand.cs new file mode 100644 index 0000000..12c856b --- /dev/null +++ b/dotnet/AipsCore/Application/Models/User/Command/RefreshLogIn/RefreshLogInCommand.cs @@ -0,0 +1,6 @@ +using AipsCore.Application.Abstract.Command; +using AipsCore.Application.Common.Authentication.Dtos; + +namespace AipsCore.Application.Models.User.Command.RefreshLogIn; + +public record RefreshLogInCommand(string RefreshToken) : ICommand; \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/RefreshLogIn/RefreshLogInCommandHandler.cs b/dotnet/AipsCore/Application/Models/User/Command/RefreshLogIn/RefreshLogInCommandHandler.cs new file mode 100644 index 0000000..6d1b568 --- /dev/null +++ b/dotnet/AipsCore/Application/Models/User/Command/RefreshLogIn/RefreshLogInCommandHandler.cs @@ -0,0 +1,44 @@ +using AipsCore.Application.Abstract.Command; +using AipsCore.Application.Abstract.UserContext; +using AipsCore.Application.Common.Authentication; +using AipsCore.Application.Common.Authentication.Dtos; +using AipsCore.Domain.Abstract; + +namespace AipsCore.Application.Models.User.Command.RefreshLogIn; + +public class RefreshLogInCommandHandler : ICommandHandler +{ + private readonly ITokenProvider _tokenProvider; + private readonly IRefreshTokenRepository _refreshTokenRepository; + private readonly IAuthService _authService; + private readonly IUnitOfWork _unitOfWork; + + public RefreshLogInCommandHandler( + ITokenProvider tokenProvider, + IRefreshTokenRepository refreshTokenRepository, + IAuthService authService, + IUnitOfWork unitOfWork) + { + _tokenProvider = tokenProvider; + _refreshTokenRepository = refreshTokenRepository; + _authService = authService; + _unitOfWork = unitOfWork; + } + + public async Task Handle(RefreshLogInCommand command, CancellationToken cancellationToken = default) + { + var refreshToken = await _refreshTokenRepository.GetByValueAsync(command.RefreshToken, cancellationToken); + + var loginResult = await _authService.LoginWithRefreshTokenAsync(refreshToken, cancellationToken); + + var newAccessToken = _tokenProvider.GenerateAccessToken(loginResult.User, loginResult.Roles); + var newRefreshToken = _tokenProvider.GenerateRefreshToken(); + + await _refreshTokenRepository.RevokeAsync(refreshToken.Value, cancellationToken); + await _refreshTokenRepository.AddAsync(newRefreshToken, loginResult.User.Id, cancellationToken); + + await _unitOfWork.SaveChangesAsync(cancellationToken); + + return new LogInUserResultDto(newAccessToken, newRefreshToken); + } +} \ No newline at end of file diff --git a/dotnet/AipsCore/Application/Models/User/Command/SignUp/SignUpUserCommandHandler.cs b/dotnet/AipsCore/Application/Models/User/Command/SignUp/SignUpUserCommandHandler.cs index 925c22f..0c67df8 100644 --- a/dotnet/AipsCore/Application/Models/User/Command/SignUp/SignUpUserCommandHandler.cs +++ b/dotnet/AipsCore/Application/Models/User/Command/SignUp/SignUpUserCommandHandler.cs @@ -1,19 +1,15 @@ using AipsCore.Application.Abstract.Command; using AipsCore.Application.Common.Authentication; -using AipsCore.Domain.Abstract; -using AipsCore.Domain.Models.User.External; using AipsCore.Domain.Models.User.ValueObjects; namespace AipsCore.Application.Models.User.Command.SignUp; public class SignUpUserCommandHandler : ICommandHandler { - private readonly IUserRepository _userRepository; private readonly IAuthService _authService; - public SignUpUserCommandHandler(IUserRepository userRepository, IAuthService authService) + public SignUpUserCommandHandler(IAuthService authService) { - _userRepository = userRepository; _authService = authService; }