From 0fbb94b86eec0dc73e9a9fdac0a98ef787956fea Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 25 Feb 2024 15:54:32 +0000 Subject: [PATCH] refactor: move authentication to dedicated controller --- OliverBooth/Controllers/AdminController.cs | 84 ------------- .../Api/v1/AuthenticationController.cs | 116 ++++++++++++++++++ OliverBooth/Pages/Admin/Login.cshtml | 2 +- OliverBooth/Pages/Shared/_AdminLayout.cshtml | 6 +- 4 files changed, 122 insertions(+), 86 deletions(-) delete mode 100644 OliverBooth/Controllers/AdminController.cs create mode 100644 OliverBooth/Controllers/Api/v1/AuthenticationController.cs diff --git a/OliverBooth/Controllers/AdminController.cs b/OliverBooth/Controllers/AdminController.cs deleted file mode 100644 index 859f028..0000000 --- a/OliverBooth/Controllers/AdminController.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Net; -using Microsoft.AspNetCore.Mvc; -using OliverBooth.Data.Web; -using OliverBooth.Services; -using ISession = OliverBooth.Data.Web.ISession; - -namespace OliverBooth.Controllers; - -[Controller] -[Route("auth/admin")] -public sealed class AdminController : ControllerBase -{ - private readonly ILogger _logger; - private readonly IUserService _userService; - private readonly ISessionService _sessionService; - - /// - /// Initializes a new instance of the class. - /// - /// The logger. - /// The user service. - /// The session service. - public AdminController(ILogger logger, - IUserService userService, - ISessionService sessionService) - { - _logger = logger; - _userService = userService; - _sessionService = sessionService; - } - - [HttpPost("login")] - public IActionResult Login() - { - string? loginEmail = Request.Form["login-email"]; - string? loginPassword = Request.Form["login-password"]; - IPAddress? remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress; - - if (string.IsNullOrWhiteSpace(loginEmail)) - { - _logger.LogInformation("Login attempt from {Host} with empty login", remoteIpAddress); - return RedirectToPage("/admin/login"); - } - - if (string.IsNullOrWhiteSpace(loginPassword)) - { - _logger.LogInformation("Login attempt as '{Email}' from {Host} with empty password", loginEmail, - remoteIpAddress); - return RedirectToPage("/admin/login"); - } - - if (_userService.VerifyLogin(loginEmail, loginPassword, out IUser? user)) - { - _logger.LogInformation("Login attempt for '{Email}' succeeded from {Host}", loginEmail, remoteIpAddress); - } - else - { - _logger.LogInformation("Login attempt for '{Email}' failed from {Host}", loginEmail, remoteIpAddress); - return RedirectToPage("/admin/login"); - } - - ISession session = _sessionService.CreateSession(Request, user); - _sessionService.SaveSessionCookie(Response, session); - return RedirectToPage("/admin/index"); - } - - [HttpGet("logout")] - public IActionResult Logout() - { - if (_sessionService.TryGetSession(Request, out ISession? session)) - { - _sessionService.DeleteSession(session); - } - - _sessionService.DeleteSessionCookie(Response); - - if (Request.Headers.Referer is var referer && !string.IsNullOrWhiteSpace(referer.ToString())) - { - return Redirect(referer!); - } - - return RedirectToPage("/admin/login"); - } -} diff --git a/OliverBooth/Controllers/Api/v1/AuthenticationController.cs b/OliverBooth/Controllers/Api/v1/AuthenticationController.cs new file mode 100644 index 0000000..98d7c20 --- /dev/null +++ b/OliverBooth/Controllers/Api/v1/AuthenticationController.cs @@ -0,0 +1,116 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Mvc; +using OliverBooth.Data.Web; +using OliverBooth.Services; +using ISession = OliverBooth.Data.Web.ISession; + +namespace OliverBooth.Controllers.Api.v1; + +/// +/// Represents a controller which handles user authentication. +/// +[Controller] +[Route("api/v{version:apiVersion}/auth")] +[ApiVersion(1)] +public sealed class AuthenticationController : ControllerBase +{ + private readonly ILogger _logger; + private readonly ISessionService _sessionService; + private readonly IUserService _userService; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The session service. + /// The user service. + public AuthenticationController(ILogger logger, + ISessionService sessionService, + IUserService userService) + { + _logger = logger; + _sessionService = sessionService; + _userService = userService; + } + + /// + /// Authorizes a login request using the specified credentials. + /// + /// The login email address. + /// The login password. + /// The result of the authentication process. + [HttpPost("signin")] + public IActionResult DoSignIn([FromForm(Name = "login-email")] string emailAddress, + [FromForm(Name = "login-password")] string password) + { + string epName = nameof(DoSignIn); + if (Request.HttpContext.Connection.RemoteIpAddress is not { } ip) + { + _logger.LogWarning("Endpoint {Name} reached with no remote IP!", epName); + return BadRequest(); + } + + IActionResult redirectResult = RedirectToPage("/admin/login"); + if (Request.Headers.Referer is var referer && !string.IsNullOrWhiteSpace(referer.ToString())) + { + _logger.LogInformation("Endpoint {Name} reached by {Host} with referer {Referer}", epName, ip, referer); + redirectResult = Redirect(referer!); + } + + if (string.IsNullOrWhiteSpace(emailAddress)) + { + _logger.LogInformation("Login attempt from {Host} has empty login", ip); + return redirectResult; + } + + if (string.IsNullOrWhiteSpace(emailAddress)) + { + _logger.LogInformation("Login attempt from {Host} with login {Login} has empty password", ip, emailAddress); + return redirectResult; + } + + if (!_userService.VerifyLogin(emailAddress, password, out IUser? user)) + { + _logger.LogInformation("Login attempt from {Host} with login {Login} failed", ip, emailAddress); + return redirectResult; + } + + ISession session = _sessionService.CreateSession(Request, user); + _sessionService.SaveSessionCookie(Response, session); + _logger.LogInformation("Login attempt from {Host} with login {Login} succeeded", ip, emailAddress); + return redirectResult; + } + + /// + /// Signs the client out of its current session. + /// + /// The result of the sign-out process. + [HttpGet("signout")] + public IActionResult DoSignOut() + { + string epName = nameof(DoSignOut); + if (Request.HttpContext.Connection.RemoteIpAddress is not { } ip) + { + _logger.LogWarning("Endpoint {Name} reached with no remote IP!", epName); + return BadRequest(); + } + + IActionResult redirectResult = RedirectToPage("/admin/login"); + if (Request.Headers.Referer is var referer && !string.IsNullOrWhiteSpace(referer.ToString())) + { + _logger.LogInformation("Endpoint {Name} reached by {Host} with referer {Referer}", epName, ip, referer); + redirectResult = Redirect(referer!); + } + + if (!_sessionService.TryGetSession(HttpContext.Request, out ISession? session)) + { + _logger.LogInformation("Session sign-out from {Host} requested with no valid session", ip); + return redirectResult; + } + + _sessionService.DeleteSession(session); + _sessionService.DeleteSessionCookie(HttpContext.Response); + _logger.LogInformation("Session sign-out from {Host} completed successfully", ip); + return redirectResult; + } +} diff --git a/OliverBooth/Pages/Admin/Login.cshtml b/OliverBooth/Pages/Admin/Login.cshtml index 6eeb75a..348281d 100644 --- a/OliverBooth/Pages/Admin/Login.cshtml +++ b/OliverBooth/Pages/Admin/Login.cshtml @@ -6,7 +6,7 @@ }
-
+

Please sign in

diff --git a/OliverBooth/Pages/Shared/_AdminLayout.cshtml b/OliverBooth/Pages/Shared/_AdminLayout.cshtml index 9559134..a3f70cd 100644 --- a/OliverBooth/Pages/Shared/_AdminLayout.cshtml +++ b/OliverBooth/Pages/Shared/_AdminLayout.cshtml @@ -126,7 +126,11 @@
  • Settings
  • Profile
  • -
  • Sign out
  • +
  • + + Sign out + +