using System.Security.Claims; using System.Security.Cryptography; using System.Text.Json; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using SIGCM2.Application.Abstractions.Security; using SIGCM2.Domain.Entities; namespace SIGCM2.Infrastructure.Security; public sealed class JwtService : IJwtService { private readonly RSA _rsa; private readonly JwtOptions _options; public JwtService(RSA rsa, JwtOptions options) { _rsa = rsa; _options = options; } /// public ClaimsPrincipal GetPrincipalFromExpiredToken(string accessToken) { var parameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = _options.Issuer, ValidateAudience = true, ValidAudience = _options.Audience, ValidateIssuerSigningKey = true, IssuerSigningKey = new RsaSecurityKey(_rsa), ValidateLifetime = false, // Key: accept expired tokens in refresh flow ClockSkew = TimeSpan.Zero, }; var handler = new JwtSecurityTokenHandler(); var principal = handler.ValidateToken(accessToken, parameters, out var securityToken); if (securityToken is not JwtSecurityToken jwt || !jwt.Header.Alg.Equals(SecurityAlgorithms.RsaSha256, StringComparison.OrdinalIgnoreCase)) throw new SecurityTokenException("Invalid token algorithm"); return principal; } public string GenerateAccessToken(Usuario usuario) { var signingKey = new RsaSecurityKey(_rsa); var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256); var permisos = DeserializePermisos(usuario.PermisosJson); var claims = new List { new(JwtRegisteredClaimNames.Sub, usuario.Id.ToString()), new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new("name", usuario.Username), new("rol", usuario.Rol), }; // Add each permission as a separate claim foreach (var permiso in permisos) claims.Add(new Claim("permisos", permiso)); var now = DateTime.UtcNow; var descriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(claims), Issuer = _options.Issuer, Audience = _options.Audience, IssuedAt = now, Expires = now.AddMinutes(_options.AccessTokenMinutes), SigningCredentials = credentials }; var handler = new JwtSecurityTokenHandler(); var token = handler.CreateToken(descriptor); return handler.WriteToken(token); } private static string[] DeserializePermisos(string permisosJson) { try { return JsonSerializer.Deserialize(permisosJson) ?? []; } catch { return []; } } }