2026-01-30 00:18:25 +01:00
|
|
|
|
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;
|
2026-01-20 02:14:01 +01:00
|
|
|
|
|
|
|
|
|
|
namespace TimetableDesigner.Backend.Services.Authentication.Core.Helpers;
|
|
|
|
|
|
|
2026-02-05 23:51:49 +01:00
|
|
|
|
public class AccessTokenGenerator : IAccessTokenGenerator
|
2026-01-20 02:14:01 +01:00
|
|
|
|
{
|
2026-01-30 00:18:25 +01:00
|
|
|
|
private readonly IConfiguration _configuration;
|
|
|
|
|
|
private readonly DatabaseContext _databaseContext;
|
|
|
|
|
|
|
2026-02-05 23:51:49 +01:00
|
|
|
|
public AccessTokenGenerator(IConfiguration configuration, DatabaseContext databaseContext)
|
2026-01-20 02:14:01 +01:00
|
|
|
|
{
|
2026-01-30 00:18:25 +01:00
|
|
|
|
_configuration = configuration;
|
|
|
|
|
|
_databaseContext = databaseContext;
|
2026-01-20 02:14:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string GenerateAccessToken(Account account)
|
|
|
|
|
|
{
|
2026-01-30 00:18:25 +01:00
|
|
|
|
IConfigurationSection accessTokenSettings = _configuration.GetSection("Tokens")
|
|
|
|
|
|
.GetSection("AccessToken");
|
|
|
|
|
|
|
|
|
|
|
|
int lifetime = accessTokenSettings.GetSection("Lifetime")
|
|
|
|
|
|
.GetValue<int>("Normal");
|
|
|
|
|
|
DateTimeOffset expirationDate = DateTimeOffset.UtcNow.AddMinutes(lifetime);
|
2026-01-20 02:14:01 +01:00
|
|
|
|
|
2026-01-30 00:18:25 +01:00
|
|
|
|
string stringKey = accessTokenSettings.GetValue<string>("Key")!;
|
|
|
|
|
|
byte[] encodedKey = Encoding.UTF8.GetBytes(stringKey);
|
|
|
|
|
|
SymmetricSecurityKey key = new SymmetricSecurityKey(encodedKey);
|
|
|
|
|
|
|
|
|
|
|
|
string algorithm = accessTokenSettings.GetValue<string>("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<string>("Issuer"),
|
|
|
|
|
|
Audience = accessTokenSettings.GetValue<string>("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);
|
2026-01-20 02:14:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-05 23:51:49 +01:00
|
|
|
|
public RefreshToken GenerateRefreshToken(bool isExtendable)
|
2026-01-20 02:14:01 +01:00
|
|
|
|
{
|
2026-02-02 20:34:29 +01:00
|
|
|
|
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);
|
|
|
|
|
|
|
2026-02-05 23:51:49 +01:00
|
|
|
|
return new RefreshToken
|
2026-02-02 20:34:29 +01:00
|
|
|
|
{
|
|
|
|
|
|
Token = guid,
|
|
|
|
|
|
ExpirationDate = expirationDate,
|
|
|
|
|
|
IsExtendable = isExtendable,
|
|
|
|
|
|
};
|
2026-01-20 02:14:01 +01:00
|
|
|
|
}
|
2026-02-05 23:51:49 +01:00
|
|
|
|
|
|
|
|
|
|
public bool ValidateExpiredAccessToken(string accessToken)
|
2026-01-20 02:14:01 +01:00
|
|
|
|
{
|
2026-02-05 23:51:49 +01:00
|
|
|
|
IConfigurationSection accessTokenSettings = _configuration.GetSection("Tokens")
|
|
|
|
|
|
.GetSection("AccessToken");
|
|
|
|
|
|
|
|
|
|
|
|
string stringKey = accessTokenSettings.GetValue<string>("Key")!;
|
|
|
|
|
|
byte[] encodedKey = Encoding.UTF8.GetBytes(stringKey);
|
|
|
|
|
|
SymmetricSecurityKey key = new SymmetricSecurityKey(encodedKey);
|
|
|
|
|
|
|
|
|
|
|
|
string algorithm = accessTokenSettings.GetValue<string>("Algorithm")!;
|
|
|
|
|
|
|
|
|
|
|
|
TokenValidationParameters tokenValidation = new TokenValidationParameters
|
|
|
|
|
|
{
|
|
|
|
|
|
ValidateIssuerSigningKey = true,
|
|
|
|
|
|
ValidateAudience = true,
|
|
|
|
|
|
ValidateIssuer = true,
|
|
|
|
|
|
ValidateLifetime = false,
|
|
|
|
|
|
ValidIssuer = accessTokenSettings.GetValue<string>("Issuer"),
|
|
|
|
|
|
ValidAudience = accessTokenSettings.GetValue<string>("Audience"),
|
|
|
|
|
|
IssuerSigningKey = key,
|
|
|
|
|
|
ClockSkew = TimeSpan.FromMinutes(1),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
|
|
|
|
|
|
tokenHandler.ValidateToken(accessToken, tokenValidation, out SecurityToken validatedToken);
|
|
|
|
|
|
JwtSecurityToken? jwtSecurityToken = validatedToken as JwtSecurityToken;
|
|
|
|
|
|
|
|
|
|
|
|
return jwtSecurityToken is not null && jwtSecurityToken.Header.Alg.Equals(algorithm, StringComparison.InvariantCultureIgnoreCase);
|
2026-01-30 00:18:25 +01:00
|
|
|
|
}
|
2026-01-20 02:14:01 +01:00
|
|
|
|
}
|