diff --git a/UserManagement.API/Controllers/AuthController.cs b/UserManagement.API/Controllers/AuthController.cs index 5fdca72..53447d6 100644 --- a/UserManagement.API/Controllers/AuthController.cs +++ b/UserManagement.API/Controllers/AuthController.cs @@ -1,9 +1,6 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; -using System.Security.Claims; using UserManagement.Application.Dtos.Auth; using UserManagement.Application.Interfaces; @@ -16,75 +13,57 @@ namespace UserManagement.API.Controllers // CTOR private readonly IUserService _userService; private readonly IAuthService _authService; - public AuthController(IUserService userService, IAuthService authService) + private readonly ILogger _logger; + + public AuthController(IUserService userService, IAuthService authService, ILogger logger) { _userService = userService; _authService = authService; + _logger = logger; } - // LOGIN - [AllowAnonymous] + // SIGN IN [HttpPost("login")] [SwaggerOperation(Summary = "Login")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task Login([FromBody] LoginDto login) { - // Validate user - var user = await _userService.GetUserByUsernameAsync(login.Username, includeRoles: true); - if (user is null) + try { - return Unauthorized("Benutzername und Passwort stimmen nicht überein!"); + await _authService.SignInAsync(login.Username, login.Password, HttpContext); + return Ok(); } - - // Validate login credentials - var isValid = await _authService.ValidateAsync(login.Username, login.Password); - if (!isValid) + catch (UnauthorizedAccessException ex) { - return Unauthorized("Benutzername und Passwort stimmen nicht überein!"); + _logger.LogError(ex, ex.Message); + return Unauthorized(ex.Message); } - - // Create claims based on the user information - var claims = new List + catch (Exception ex) { - new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), - new Claim(ClaimTypes.Name, user.UserName), - new Claim(ClaimTypes.Surname, user.LastName ?? ""), - new Claim(ClaimTypes.GivenName, user.FirstName ?? ""), - }; - - foreach (var userRole in user.UserRoles) - { - claims.Add(new Claim(ClaimTypes.Role, userRole!.Name)); + _logger.LogError(ex, ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError); } - - // Create a ClaimsIdentity based on the created claims - var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); - - // Set the authentication properties - var authProperties = new AuthenticationProperties - { - IsPersistent = true, - AllowRefresh = true, - ExpiresUtc = DateTime.UtcNow.AddMinutes(60) - }; - - // Sign in user using cookie-based authentication - await HttpContext.SignInAsync( - CookieAuthenticationDefaults.AuthenticationScheme, - new ClaimsPrincipal(claimsIdentity), - authProperties - ); - - return Ok(); } // LOGOUT [HttpPost("logout")] [SwaggerOperation(Summary = "Logout")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] public async Task Logout() { - await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - - return Ok(); + try + { + await _authService.SignOutAsync(HttpContext); + return Ok(); + } + catch (Exception ex) + { + _logger.LogError(ex, ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError); + } } // AUTH CHECK diff --git a/UserManagement.API/Controllers/UserController.cs b/UserManagement.API/Controllers/UserController.cs index 99031bf..425eeec 100644 --- a/UserManagement.API/Controllers/UserController.cs +++ b/UserManagement.API/Controllers/UserController.cs @@ -8,7 +8,7 @@ namespace UserManagement.API.Controllers { [Route("api/[controller]")] [ApiController] - //[Authorize(Roles = "Admin")] + [Authorize(Roles = "Admin")] public class UserController : Controller { // CTOR diff --git a/UserManagement.App/Interfaces/IAuthService.cs b/UserManagement.App/Interfaces/IAuthService.cs index 85135c2..51766e9 100644 --- a/UserManagement.App/Interfaces/IAuthService.cs +++ b/UserManagement.App/Interfaces/IAuthService.cs @@ -1,8 +1,15 @@ -namespace UserManagement.Application.Interfaces +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; + +namespace UserManagement.Application.Interfaces { public interface IAuthService { - // AUTHENTICATE - Task ValidateAsync(string username, string password); + // SIGN IN + Task SignInAsync(string username, string password, HttpContext httpContext); + + // SIGN OUT + Task SignOutAsync(HttpContext httpContext); } } diff --git a/UserManagement.App/Services/AuthService.cs b/UserManagement.App/Services/AuthService.cs index 55fb7ff..97deb02 100644 --- a/UserManagement.App/Services/AuthService.cs +++ b/UserManagement.App/Services/AuthService.cs @@ -1,4 +1,8 @@ -using UserManagement.Application.Interfaces; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Http; +using System.Security.Claims; +using UserManagement.Application.Interfaces; using UserManagement.Infrastructure.Interfaces; namespace UserManagement.Application.Services @@ -12,12 +16,46 @@ namespace UserManagement.Application.Services _userRepository = userRepository; } - // AUTHENTICATE - public async Task ValidateAsync(string username, string password) + // LOGIN + public async Task SignInAsync(string username, string password, HttpContext httpContext) { var user = await _userRepository.GetByUsernameAsync(username, includeRoles: true); - return BCrypt.Net.BCrypt.Verify(password, user!.PasswordHash); + if (user == null || !BCrypt.Net.BCrypt.Verify(password, user.PasswordHash)) + { + throw new UnauthorizedAccessException("Benutzername und Passwort stimmen nicht überein!"); + } + + var claims = new List + { + new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), + new Claim(ClaimTypes.Name, user.UserName), + new Claim(ClaimTypes.Surname, user.LastName ?? ""), + new Claim(ClaimTypes.GivenName, user.FirstName ?? "") + }; + + claims.AddRange(user.UserRoles.Select(role => new Claim(ClaimTypes.Role, role.Role.Name))); + + var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); + + var authProperties = new AuthenticationProperties + { + IsPersistent = true, + AllowRefresh = true, + ExpiresUtc = DateTime.UtcNow.AddMinutes(60) + }; + + var principal = new ClaimsPrincipal(claimsIdentity); + + await httpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, authProperties); + + return principal; + } + + // LOGOUT + public async Task SignOutAsync(HttpContext httpContext) + { + await httpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); } } }