From dc12ee75e54f2cde5a6477e3ef986def053d1ef0 Mon Sep 17 00:00:00 2001 From: Mateusz Skoczek Date: Fri, 30 Jan 2026 00:18:25 +0100 Subject: [PATCH] access token generation added --- .../AuthPassword/AuthPasswordHandler.cs | 6 +- .../Commands/Register/RegisterHandler.cs | 20 ++++--- .../Helpers/ITokenGenerator.cs | 10 ++++ .../Helpers/TokenGenerator.cs | 55 ++++++++++++++++--- ...ackend.Services.Authentication.Core.csproj | 1 + .../Program.cs | 1 + ...ner.Backend.Services.Authentication.csproj | 2 +- .../appsettings.json | 17 ++++++ 8 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 TimetableDesigner.Backend.Services.Authentication.Core/Helpers/ITokenGenerator.cs diff --git a/TimetableDesigner.Backend.Services.Authentication.Core/Commands/AuthPassword/AuthPasswordHandler.cs b/TimetableDesigner.Backend.Services.Authentication.Core/Commands/AuthPassword/AuthPasswordHandler.cs index 9c78dbe..c9412d9 100644 --- a/TimetableDesigner.Backend.Services.Authentication.Core/Commands/AuthPassword/AuthPasswordHandler.cs +++ b/TimetableDesigner.Backend.Services.Authentication.Core/Commands/AuthPassword/AuthPasswordHandler.cs @@ -10,11 +10,13 @@ public class AuthPasswordHandler : IRequestHandler Handle(AuthPasswordCommand request, CancellationToken cancellationToken) @@ -31,6 +33,8 @@ public class AuthPasswordHandler : IRequestHandler public async Task Handle(RegisterCommand command, CancellationToken cancellationToken) { PasswordHashData hash = _passwordHasher.CreateHash(command.Password); - + Account account = new Account { Email = command.Email, Password = hash.Hash, PasswordSalt = hash.Salt, }; - await _databaseContext.Accounts.AddAsync(account, cancellationToken); - await _databaseContext.SaveChangesAsync(cancellationToken); - - Event eventData = Event.Create(new RegisterEvent(account.Id, account.Email)); - await _databaseContext.Events.AddAsync(eventData, cancellationToken); - await _databaseContext.SaveChangesAsync(cancellationToken); + await using (IDbContextTransaction transaction = await _databaseContext.Database.BeginTransactionAsync(cancellationToken)) + { + await _databaseContext.Accounts.AddAsync(account, cancellationToken); + await _databaseContext.SaveChangesAsync(cancellationToken); + + Event eventData = Event.Create(new RegisterEvent(account.Id, account.Email)); + await _databaseContext.Events.AddAsync(eventData, cancellationToken); + await _databaseContext.SaveChangesAsync(cancellationToken); + + await transaction.CommitAsync(cancellationToken); + } return new RegisterResult(account.Id, account.Email); } diff --git a/TimetableDesigner.Backend.Services.Authentication.Core/Helpers/ITokenGenerator.cs b/TimetableDesigner.Backend.Services.Authentication.Core/Helpers/ITokenGenerator.cs new file mode 100644 index 0000000..ade35da --- /dev/null +++ b/TimetableDesigner.Backend.Services.Authentication.Core/Helpers/ITokenGenerator.cs @@ -0,0 +1,10 @@ +using TimetableDesigner.Backend.Services.Authentication.Database.Model; + +namespace TimetableDesigner.Backend.Services.Authentication.Core.Helpers; + +public interface ITokenGenerator +{ + string GenerateAccessToken(Account account); + Task GenerateRefreshTokenAsync(Account account); + Task ExtendRefreshTokenAsync(); +} \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication.Core/Helpers/TokenGenerator.cs b/TimetableDesigner.Backend.Services.Authentication.Core/Helpers/TokenGenerator.cs index 16848cb..73658d7 100644 --- a/TimetableDesigner.Backend.Services.Authentication.Core/Helpers/TokenGenerator.cs +++ b/TimetableDesigner.Backend.Services.Authentication.Core/Helpers/TokenGenerator.cs @@ -1,27 +1,68 @@ -using Microsoft.Extensions.Configuration; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using Microsoft.Extensions.Configuration; +using Microsoft.IdentityModel.Tokens; +using TimetableDesigner.Backend.Services.Authentication.Database; +using TimetableDesigner.Backend.Services.Authentication.Database.Model; +using JwtRegisteredClaimNames = Microsoft.IdentityModel.JsonWebTokens.JwtRegisteredClaimNames; namespace TimetableDesigner.Backend.Services.Authentication.Core.Helpers; -public class TokenGenerator +public class TokenGenerator : ITokenGenerator { - /* + private readonly IConfiguration _configuration; + private readonly DatabaseContext _databaseContext; + public TokenGenerator(IConfiguration configuration, DatabaseContext databaseContext) { - + _configuration = configuration; + _databaseContext = databaseContext; } public string GenerateAccessToken(Account account) { + IConfigurationSection accessTokenSettings = _configuration.GetSection("Tokens") + .GetSection("AccessToken"); + + int lifetime = accessTokenSettings.GetSection("Lifetime") + .GetValue("Normal"); + DateTimeOffset expirationDate = DateTimeOffset.UtcNow.AddMinutes(lifetime); + string stringKey = accessTokenSettings.GetValue("Key")!; + byte[] encodedKey = Encoding.UTF8.GetBytes(stringKey); + SymmetricSecurityKey key = new SymmetricSecurityKey(encodedKey); + + string algorithm = accessTokenSettings.GetValue("Algorithm")!; + + SecurityTokenDescriptor descriptor = new SecurityTokenDescriptor + { + Subject = new ClaimsIdentity( + [ + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim(JwtRegisteredClaimNames.Sub, account.Id.ToString()), + new Claim(JwtRegisteredClaimNames.Exp, expirationDate.UtcTicks.ToString()) + ]), + Issuer = accessTokenSettings.GetValue("Issuer"), + Audience = accessTokenSettings.GetValue("Audience"), + SigningCredentials = new SigningCredentials(key, algorithm), + Expires = expirationDate.UtcDateTime, + }; + + JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler(); + handler.InboundClaimTypeMap.Clear(); + SecurityToken token = handler.CreateToken(descriptor); + + return handler.WriteToken(token); } public async Task GenerateRefreshTokenAsync(Account account) { - + return null; } public async Task ExtendRefreshTokenAsync() { - - }*/ + return null; + } } \ No newline at end of file diff --git a/TimetableDesigner.Backend.Services.Authentication.Core/TimetableDesigner.Backend.Services.Authentication.Core.csproj b/TimetableDesigner.Backend.Services.Authentication.Core/TimetableDesigner.Backend.Services.Authentication.Core.csproj index a4ffee4..a2f06cc 100644 --- a/TimetableDesigner.Backend.Services.Authentication.Core/TimetableDesigner.Backend.Services.Authentication.Core.csproj +++ b/TimetableDesigner.Backend.Services.Authentication.Core/TimetableDesigner.Backend.Services.Authentication.Core.csproj @@ -14,6 +14,7 @@ + diff --git a/TimetableDesigner.Backend.Services.Authentication/Program.cs b/TimetableDesigner.Backend.Services.Authentication/Program.cs index 40b0cd4..b1849f5 100644 --- a/TimetableDesigner.Backend.Services.Authentication/Program.cs +++ b/TimetableDesigner.Backend.Services.Authentication/Program.cs @@ -52,6 +52,7 @@ public static class Program private static IServiceCollection AddHelpers(this IServiceCollection services) { services.AddSingleton(); + services.AddScoped(); return services; } diff --git a/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj b/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj index c92c4f5..d740385 100644 --- a/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj +++ b/TimetableDesigner.Backend.Services.Authentication/TimetableDesigner.Backend.Services.Authentication.csproj @@ -19,7 +19,7 @@ - + diff --git a/TimetableDesigner.Backend.Services.Authentication/appsettings.json b/TimetableDesigner.Backend.Services.Authentication/appsettings.json index 05d2018..62af5b6 100644 --- a/TimetableDesigner.Backend.Services.Authentication/appsettings.json +++ b/TimetableDesigner.Backend.Services.Authentication/appsettings.json @@ -9,5 +9,22 @@ "ConnectionStrings": { "Database": "Host=localhost;Port=5433;Database=ttd_authentication;Username=postgres;Password=l4JxOIuSoyod86N;Include Error Detail=True", "EventQueue": "Hostname=localhost;Port=5672;Username=user;Password=l4JxOIuSoyod86N;ExchangeName=events;QueuePrefix=authentication" + }, + "Tokens": { + "AccessToken": { + "Lifetime": { + "Normal": 5 + }, + "Issuer": "auth.timetabledesigner.com", + "Audience": "timetabledesigner.com", + "Key": "testkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytestkeytest", + "Algorithm": "HS512" + }, + "RefreshToken": { + "Lifetime": { + "Normal": 1440, + "Extended": 10080 + } + } } }