auth token endpoint finished

This commit is contained in:
2026-02-06 00:10:00 +01:00
Unverified
parent c5823dc6fc
commit 81455ab636
7 changed files with 49 additions and 53 deletions

View File

@@ -10,13 +10,13 @@ public class AuthPasswordHandler : IRequestHandler<AuthPasswordCommand, AuthPass
{
private readonly DatabaseContext _databaseContext;
private readonly IPasswordHasher _passwordHasher;
private readonly IAccessTokenGenerator _accessTokenGenerator;
private readonly ITokenHelper _tokenHelper;
public AuthPasswordHandler(DatabaseContext databaseContext, IPasswordHasher passwordHasher, IAccessTokenGenerator accessTokenGenerator)
public AuthPasswordHandler(DatabaseContext databaseContext, IPasswordHasher passwordHasher, ITokenHelper tokenHelper)
{
_databaseContext = databaseContext;
_passwordHasher = passwordHasher;
_accessTokenGenerator = accessTokenGenerator;
_tokenHelper = tokenHelper;
}
public async Task<AuthPasswordResult> Handle(AuthPasswordCommand request, CancellationToken cancellationToken)
@@ -33,10 +33,17 @@ public class AuthPasswordHandler : IRequestHandler<AuthPasswordCommand, AuthPass
return AuthPasswordResult.Failure();
}
string accessToken = _accessTokenGenerator.GenerateAccessToken(account);
RefreshToken refreshToken = _accessTokenGenerator.GenerateRefreshToken(request.RememberMe);
string accessToken = _tokenHelper.GenerateAccessToken(account.Id);
account.RefreshTokens.Add(refreshToken);
RefreshToken refreshToken = new RefreshToken
{
Token = Guid.NewGuid(),
IsExtendable = request.RememberMe,
AccountId = account.Id,
ExpirationDate = _tokenHelper.CalculateRefreshTokenExpirationDate(request.RememberMe),
};
await _databaseContext.RefreshTokens.AddAsync(refreshToken, cancellationToken);
await _databaseContext.SaveChangesAsync(cancellationToken);
return AuthPasswordResult.Success(accessToken, refreshToken.Token.ToString());

View File

@@ -9,31 +9,32 @@ namespace TimetableDesigner.Backend.Services.Authentication.Core.Commands.AuthTo
public class AuthTokenHandler : IRequestHandler<AuthTokenCommand, AuthTokenResult>
{
private readonly DatabaseContext _databaseContext;
private readonly IAccessTokenGenerator _accessTokenGenerator;
private readonly ITokenHelper _tokenHelper;
public AuthTokenHandler(DatabaseContext databaseContext, IAccessTokenGenerator accessTokenGenerator)
public AuthTokenHandler(DatabaseContext databaseContext, ITokenHelper tokenHelper)
{
_databaseContext = databaseContext;
_accessTokenGenerator = accessTokenGenerator;
_tokenHelper = tokenHelper;
}
public async Task<AuthTokenResult> Handle(AuthTokenCommand request, CancellationToken cancellationToken)
{
RefreshToken? token = await _databaseContext.RefreshTokens
RefreshToken? refreshToken = await _databaseContext.RefreshTokens
.Include(x => x.Account)
.FirstOrDefaultAsync(x => x.Token == Guid.Parse(request.RefreshToken), cancellationToken);
if (token is null || token.ExpirationDate < DateTimeOffset.UtcNow || !_accessTokenGenerator.ValidateExpiredAccessToken(request.AccessToken))
if (refreshToken is null || refreshToken.ExpirationDate < DateTimeOffset.UtcNow || !_tokenHelper.ValidateExpiredAccessToken(request.AccessToken))
{
return AuthTokenResult.Failure();
}
string accessToken = _accessTokenGenerator.GenerateAccessToken(token.Account);
if (token.IsExtendable)
{
}
string accessToken = _tokenHelper.GenerateAccessToken(refreshToken.Account.Id);
if (refreshToken.IsExtendable)
{
refreshToken.ExpirationDate = _tokenHelper.CalculateRefreshTokenExpirationDate();
await _databaseContext.SaveChangesAsync(cancellationToken);
}
return AuthTokenResult.Success(refreshToken, accessToken);
return AuthTokenResult.Success(accessToken, refreshToken.Token.ToString());
}
}

View File

@@ -2,9 +2,9 @@
namespace TimetableDesigner.Backend.Services.Authentication.Core.Helpers;
public interface IAccessTokenGenerator
public interface ITokenHelper
{
string GenerateAccessToken(Account account);
RefreshToken GenerateRefreshToken(bool isExtendable);
string GenerateAccessToken(long accountId);
bool ValidateExpiredAccessToken(string accessToken);
DateTimeOffset CalculateRefreshTokenExpirationDate(bool isExtendable = true);
}

View File

@@ -1,6 +0,0 @@
namespace TimetableDesigner.Backend.Services.Authentication.Core.Helpers;
public record PasswordHashData(
byte[] Hash,
string Salt
);

View File

@@ -36,4 +36,9 @@ public class PasswordHasher : IPasswordHasher
byte[] hash = hashFunction.GetBytes(32);
return hash;
}
}
}
public record PasswordHashData(
byte[] Hash,
string Salt
);

View File

@@ -9,18 +9,16 @@ using JwtRegisteredClaimNames = Microsoft.IdentityModel.JsonWebTokens.JwtRegiste
namespace TimetableDesigner.Backend.Services.Authentication.Core.Helpers;
public class AccessTokenGenerator : IAccessTokenGenerator
public class TokenHelper : ITokenHelper
{
private readonly IConfiguration _configuration;
private readonly DatabaseContext _databaseContext;
public AccessTokenGenerator(IConfiguration configuration, DatabaseContext databaseContext)
public TokenHelper(IConfiguration configuration)
{
_configuration = configuration;
_databaseContext = databaseContext;
}
public string GenerateAccessToken(Account account)
public string GenerateAccessToken(long accountId)
{
IConfigurationSection accessTokenSettings = _configuration.GetSection("Tokens")
.GetSection("AccessToken");
@@ -40,7 +38,7 @@ public class AccessTokenGenerator : IAccessTokenGenerator
Subject = new ClaimsIdentity(
[
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Sub, account.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Sub, accountId.ToString()),
new Claim(JwtRegisteredClaimNames.Exp, expirationDate.UtcTicks.ToString())
]),
Issuer = accessTokenSettings.GetValue<string>("Issuer"),
@@ -56,25 +54,6 @@ public class AccessTokenGenerator : IAccessTokenGenerator
return handler.WriteToken(token);
}
public RefreshToken GenerateRefreshToken(bool isExtendable)
{
string lifetimeSection = isExtendable ? "Extended" : "Normal";
int lifetime = _configuration.GetSection("Tokens")
.GetSection("RefreshToken")
.GetSection("Lifetime")
.GetValue<int>(lifetimeSection);
Guid guid = Guid.NewGuid();
DateTimeOffset expirationDate = DateTimeOffset.UtcNow.AddMinutes(lifetime);
return new RefreshToken
{
Token = guid,
ExpirationDate = expirationDate,
IsExtendable = isExtendable,
};
}
public bool ValidateExpiredAccessToken(string accessToken)
{
IConfigurationSection accessTokenSettings = _configuration.GetSection("Tokens")
@@ -104,4 +83,14 @@ public class AccessTokenGenerator : IAccessTokenGenerator
return jwtSecurityToken is not null && jwtSecurityToken.Header.Alg.Equals(algorithm, StringComparison.InvariantCultureIgnoreCase);
}
public DateTimeOffset CalculateRefreshTokenExpirationDate(bool isExtendable = true)
{
string lifetimeSection = isExtendable ? "Extended" : "Normal";
int lifetime = _configuration.GetSection("Tokens")
.GetSection("RefreshToken")
.GetSection("Lifetime")
.GetValue<int>(lifetimeSection);
return DateTimeOffset.UtcNow.AddMinutes(lifetime);
}
}