From f275463a3ddc3ace42fab025bb73b72f31eb7bb0 Mon Sep 17 00:00:00 2001 From: eee4 <41441600+eee4@users.noreply.github.com> Date: Tue, 15 Jul 2025 12:38:02 +0200 Subject: [PATCH] feat: add db-based user log-on, invalidate tokens made for old passwords --- Controllers/AuthController.cs | 27 ++++++++++++--- Controllers/GeneralUseHelperFunctions.cs | 43 ++++++++++++++++++++---- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/Controllers/AuthController.cs b/Controllers/AuthController.cs index 5ef685e..be8be59 100644 --- a/Controllers/AuthController.cs +++ b/Controllers/AuthController.cs @@ -1,7 +1,9 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using QuotifyBE.Data; +using QuotifyBE.Entities; using QuotifyBE.DTOs; +using System.Threading.Tasks; namespace QuotifyBE.Controllers; @@ -21,14 +23,29 @@ public class AuthController : ControllerBase } [HttpPost("login")] - public IActionResult Login([FromBody] UserLoginDTO user, GeneralUseHelpers guhf) + public async Task Login([FromBody] UserLoginDTO formUser, GeneralUseHelpers guhf) { - if (user.Email == "admin" && user.Password == "password") + // Ensure the form is complete + if (formUser.Email == null || formUser.Password == null) { - var token = guhf.GenerateJwtToken(user.Email, _appsettings); - return Ok(new { token }); + return BadRequest(new {status = "error", error_msg = "Form contains missing data"}); } - return Unauthorized(); + + // Find the user with retrieved e-mail + User? user = await guhf.GetUserFromEmail(formUser.Email); + if (user == null) + { + return NotFound(new {status = "error", error_msg = "User not found"}); + } + + // Hash the password and compare with the user-provided one + string hashedFormPassword = guhf.HashWithSHA512(formUser.Password); + if (hashedFormPassword == user.PasswordHash) + { + // All set - generate the token and return it + var token = guhf.GenerateJwtToken(formUser.Email, formUser.Password); + return Ok(new { status = "ok", token }); + } else return Unauthorized(new {status = "error", error_msg = "Unknown pair of email and password"}); } [HttpGet("some_values")] diff --git a/Controllers/GeneralUseHelperFunctions.cs b/Controllers/GeneralUseHelperFunctions.cs index 8ebd531..211e7ef 100644 --- a/Controllers/GeneralUseHelperFunctions.cs +++ b/Controllers/GeneralUseHelperFunctions.cs @@ -1,13 +1,38 @@ +using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; +using QuotifyBE.Data; +using QuotifyBE.Entities; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; +using System.Security.Cryptography; using System.Text; namespace QuotifyBE.Controllers; -public class GeneralUseHelpers +public class GeneralUseHelpers(ApplicationDbContext db, IConfiguration appsettings) { - public string GenerateJwtToken(string username, IConfiguration appsettings) + private readonly ApplicationDbContext _db = db; + private readonly IConfiguration _appsettings = appsettings; + + async public Task GetUserFromEmail(string email) + { + return await _db.Users.FirstOrDefaultAsync(e => e.Email == email); + } + + + public string HashWithSHA512(string s) + { + using (var sha512 = SHA512.Create()) + { + byte[] bytes = Encoding.ASCII.GetBytes(s); + byte[] hash = sha512.ComputeHash(bytes); + string hashstring = BitConverter.ToString(hash).Replace("-", "").ToLower(); + + return hashstring; + } + } + + public string GenerateJwtToken(string username, string passwordHash) { var claims = new[] { @@ -16,16 +41,20 @@ public class GeneralUseHelpers }; var key = new SymmetricSecurityKey( - Encoding.UTF8.GetBytes(appsettings["JwtSecret"]!) - // won't be null here - otherwise Program.cs wouldn't start + // https://stackoverflow.com/questions/21978658/invalidating-json-web-tokens#comment45057142_23089839 + // passwordHash is important for invalidating tokens after a user changed their password + Encoding.UTF8.GetBytes( + // JwtSecret won't be null here - otherwise Program.cs wouldn't start + _appsettings["JwtSecret"]! + passwordHash + ) ); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( - issuer: appsettings["DomainName"]!, - audience: appsettings["DomainName"]!, + issuer: _appsettings["DomainName"]!, + audience: _appsettings["DomainName"]!, claims: claims, - expires: DateTime.Now.AddDays(7), + expires: DateTime.Now.AddMinutes(5), signingCredentials: creds );