using Microsoft.IdentityModel.Tokens; using Mirea.Api.Security.Common.Interfaces; using System; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; namespace Mirea.Api.Endpoint.Common.Services.Security; public class JwtTokenService : IAccessToken { public required string Issuer { private get; init; } public required string Audience { private get; init; } public TimeSpan Lifetime { private get; init; } public ReadOnlyMemory EncryptionKey { private get; init; } public ReadOnlyMemory SigningKey { private get; init; } public (string Token, DateTime ExpireIn) GenerateToken(string userId) { var tokenHandler = new JwtSecurityTokenHandler(); var signingKey = new SymmetricSecurityKey(SigningKey.ToArray()); var encryptionKey = new SymmetricSecurityKey(EncryptionKey.ToArray()); var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha512); var expires = DateTime.UtcNow.Add(Lifetime); var tokenDescriptor = new SecurityTokenDescriptor { Issuer = Issuer, Audience = Audience, Expires = expires, SigningCredentials = signingCredentials, Subject = new ClaimsIdentity( [ new Claim(ClaimTypes.Name, userId), // todo: get role by userId new Claim(ClaimTypes.Role, "") ]), EncryptingCredentials = new EncryptingCredentials(encryptionKey, SecurityAlgorithms.Aes256KW, SecurityAlgorithms.Aes256CbcHmacSha512) }; var token = tokenHandler.CreateToken(tokenDescriptor); return (tokenHandler.WriteToken(token), expires); } public DateTimeOffset GetExpireDateTime(string token) { var tokenHandler = new JwtSecurityTokenHandler(); var signingKey = new SymmetricSecurityKey(SigningKey.ToArray()); var encryptionKey = new SymmetricSecurityKey(EncryptionKey.ToArray()); var tokenValidationParameters = new TokenValidationParameters { ValidIssuer = Issuer, ValidAudience = Audience, IssuerSigningKey = signingKey, TokenDecryptionKey = encryptionKey, ValidateIssuer = true, ValidateAudience = true, ValidateIssuerSigningKey = true, ValidateLifetime = false }; try { var claimsPrincipal = tokenHandler.ValidateToken(token, tokenValidationParameters, out _); var expClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "exp"); if (expClaim != null && long.TryParse(expClaim.Value, out var expUnix)) return DateTimeOffset.FromUnixTimeSeconds(expUnix); } catch (SecurityTokenException) { return DateTimeOffset.MinValue; } return DateTimeOffset.MinValue; } }