Cleaned up the architecture

This commit is contained in:
OlgunR 2024-10-01 11:45:17 +02:00
parent 3df98fb399
commit 64f3dc2875
4 changed files with 83 additions and 59 deletions

View File

@ -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<AuthController> _logger;
public AuthController(IUserService userService, IAuthService authService, ILogger<AuthController> 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<IActionResult> 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<Claim>
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<IActionResult> 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

View File

@ -8,7 +8,7 @@ namespace UserManagement.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
//[Authorize(Roles = "Admin")]
[Authorize(Roles = "Admin")]
public class UserController : Controller
{
// CTOR

View File

@ -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<bool> ValidateAsync(string username, string password);
// SIGN IN
Task<ClaimsPrincipal> SignInAsync(string username, string password, HttpContext httpContext);
// SIGN OUT
Task SignOutAsync(HttpContext httpContext);
}
}

View File

@ -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<bool> ValidateAsync(string username, string password)
// LOGIN
public async Task<ClaimsPrincipal> 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<Claim>
{
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);
}
}
}