feat: add db-based user log-on, invalidate tokens made for old passwords

This commit is contained in:
2025-07-15 12:38:02 +02:00
parent d0fc4e5ef2
commit f275463a3d
2 changed files with 58 additions and 12 deletions

View File

@@ -1,7 +1,9 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using QuotifyBE.Data; using QuotifyBE.Data;
using QuotifyBE.Entities;
using QuotifyBE.DTOs; using QuotifyBE.DTOs;
using System.Threading.Tasks;
namespace QuotifyBE.Controllers; namespace QuotifyBE.Controllers;
@@ -21,14 +23,29 @@ public class AuthController : ControllerBase
} }
[HttpPost("login")] [HttpPost("login")]
public IActionResult Login([FromBody] UserLoginDTO user, GeneralUseHelpers guhf) public async Task<IActionResult> 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 BadRequest(new {status = "error", error_msg = "Form contains missing data"});
return Ok(new { token });
} }
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")] [HttpGet("some_values")]

View File

@@ -1,13 +1,38 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using QuotifyBE.Data;
using QuotifyBE.Entities;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography;
using System.Text; using System.Text;
namespace QuotifyBE.Controllers; 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<User?> 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[] var claims = new[]
{ {
@@ -16,16 +41,20 @@ public class GeneralUseHelpers
}; };
var key = new SymmetricSecurityKey( var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(appsettings["JwtSecret"]!) // https://stackoverflow.com/questions/21978658/invalidating-json-web-tokens#comment45057142_23089839
// won't be null here - otherwise Program.cs wouldn't start // 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 creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken( var token = new JwtSecurityToken(
issuer: appsettings["DomainName"]!, issuer: _appsettings["DomainName"]!,
audience: appsettings["DomainName"]!, audience: _appsettings["DomainName"]!,
claims: claims, claims: claims,
expires: DateTime.Now.AddDays(7), expires: DateTime.Now.AddMinutes(5),
signingCredentials: creds signingCredentials: creds
); );