ldap-cesi/ldap-cesi/Services/JwtService.cs

167 lines
5.9 KiB
C#

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using ldap_cesi.Context;
using ldap_cesi.Entities;
using ldap_cesi.Services.Interfaces;
using Microsoft.IdentityModel.Tokens;
namespace ldap_cesi.Services;
public class JwtService : IJwtService
{
private readonly IRsaKeyService _rsaKeyService;
private readonly IConfiguration _configuration;
private readonly PgContext _context;
private readonly ILogger<JwtService> _logger;
public JwtService(
IConfiguration configuration,
PgContext context,
IRsaKeyService rsaKeyService,
ILogger<JwtService> logger)
{
_configuration = configuration;
_context = context;
_rsaKeyService = rsaKeyService;
_logger = logger;
}
public string GenerateToken(Utilisateur utilisateur)
{
try
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, utilisateur.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.Name, utilisateur.Nom),
new Claim(ClaimTypes.Role, utilisateur.IdRoleNavigation.Nom),
new Claim(ClaimTypes.NameIdentifier, utilisateur.Id.ToString())
};
var key = new RsaSecurityKey(_rsaKeyService.GetRsaKey());
var creds = new SigningCredentials(key, SecurityAlgorithms.RsaSha256);
var tokenExpiryMinutes = _configuration.GetValue<int>("Jwt:TokenExpiryMinutes", 30);
var token = new JwtSecurityToken(
issuer: _configuration["Jwt:Issuer"],
audience: _configuration["Jwt:Audience"],
claims: claims,
expires: DateTime.UtcNow.AddMinutes(tokenExpiryMinutes),
signingCredentials: creds);
var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
utilisateur.AccessToken = tokenString;
_context.Utilisateurs.Update(utilisateur);
_context.SaveChanges();
return tokenString;
}
catch (Exception ex)
{
_logger.LogError(ex, "Une erreur s'est produitel lors de la génération du token.");
throw;
}
}
public string GetPublicKey()
{
try
{
var publicKey = _rsaKeyService.GetRsaKey().ExportSubjectPublicKeyInfo();
return Convert.ToBase64String(publicKey);
}
catch (Exception ex)
{
_logger.LogError(ex, "Une erreur s'est produite pendant la récupération de la clé.");
throw;
}
}
// Ajouter cette méthode à votre JwtService.cs
public async Task<bool> InvalidateToken(string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
// récupération du token
var jwtToken = tokenHandler.ReadJwtToken(token);
// identifiant de l'utilisateur
var userIdClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out var userId))
{
_logger.LogWarning("Erreur d'invalidation du token : Id utilisateur non trouvé ou invalide.");
return false;
}
var utilisateur = await _context.Utilisateurs.FindAsync(userId);
if (utilisateur == null)
{
_logger.LogWarning("Erreur d'invalidation du token : Utilisateur non trouvé.");
return false;
}
// delte le token stocké
utilisateur.AccessToken = null;
_context.Utilisateurs.Update(utilisateur);
await _context.SaveChangesAsync();
_logger.LogInformation($"Token invalidé pour l'utilisateur {userId}.");
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Une erreur s'est produite pendant l'invalidation du token JWT.");
return false;
}
}
public async Task<bool> ValidateToken(string token, int userId)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new RsaSecurityKey(_rsaKeyService.GetRsaKey()),
ValidateIssuer = true,
ValidateAudience = true,
ValidIssuer = _configuration["Jwt:Issuer"],
ValidAudience = _configuration["Jwt:Audience"],
ClockSkew = TimeSpan.Zero,
ValidateLifetime = true
};
var principal = tokenHandler.ValidateToken(token, validationParameters, out var validatedToken);
var nameIdClaim = principal.FindFirst(ClaimTypes.NameIdentifier);
if (nameIdClaim == null || !int.TryParse(nameIdClaim.Value, out var tokenUserId) || tokenUserId != userId)
{
_logger.LogWarning("Erreur de validation : Id utilisateur invalide.");
return false;
}
var utilisateur = await _context.Utilisateurs.FindAsync(userId);
if (utilisateur == null)
{
_logger.LogWarning("Erreur de validation : Utilisateur non trouvé.");
return false;
}
utilisateur.AccessToken = token;
_context.Utilisateurs.Update(utilisateur);
await _context.SaveChangesAsync();
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Une erreur s'est produite lors pendant la validation du token JWT.");
return false;
}
}
}