Mettre en place l'authentification JWT avec l'API web ASP.NET ?

Le standard JSON Web Token (JWT) est utilisé pour assurer la sécurité d'un échange avec une API. Il repose sur un jeton constitué d'un entête, d'un corps et d'une signature numérique créée en plusieurs étapes. L'entête et le corps sont d'abord encodés puis concaténés. La chaîne obtenue est ensuite encodée avec une clé secrète pour obtenir la signature. Ce standard peut être utilisé par la plupart des langages, y compris en ASP .NET.

Le gestionnaire de paquets NuGet met à disposition plusieurs paquets vous permettant de générer votre propre jeton. Microsoft a mis en ligne le sien : "System.IdentityModel.Tokens.Jwt". Dans ce paquet, on retrouve la classe "SymmetricKey" qui permet de générer des clés sécurisées à partir d'un encodage. Le standard JWT en accepte plusieurs, notamment HMACSHA256. Dans cet exemple, on se sert du délai d'expiration et du nom d'utilisateur pour générer un token simple. On fait également appel à la classe "ClaimIdentity", qui permet de gérer l'authentification par revendication et ainsi utiliser uniquement le nom d'utilisateur pour le reconnaître.

public static string GenererJeton(string nomUtilisateur, int delaiExpiration = 20)
{
  //Méthode de génération d'une phrase secrète de cryptage
  var hmac = new HMACSHA256();
  var cle = Convert.ToBase64String(hmac.Key);
  var gestionJeton = new JwtSecurityTokenHandler();
  var maintenant = DateTime.UtcNow;
  var tokenDescriptor = new SecurityTokenDescriptor
  {
    Subject = new ClaimsIdentity(new[]
    {
      new Claim(ClaimTypes.Name, nomUtilisateur)
    }),
    momentExpiration = maintenant.AddMinutes(Convert.ToInt32(delaiExpiration)),
    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(cle), SecurityAlgorithms.HmacSha256Signature)
  };
  var stoken = gestionJeton.CreateToken(tokenDescriptor);
  var jeton = gestionJeton.WriteToken(stoken);
  return jeton;
}

Une fois le token généré et envoyé, c'est à votre API de le décoder pour identifier l'utilisateur. Ce sont les classes "JwtSecurityTokenHandler" et "TokenValidationParameters" qui vont être utilisées pour valider le jeton en récupérant le nom d'utilisateur contenu dedans.

public static ClaimsPrincipal GetPrincipal(string jeton)
{
  //Méthode de génération de la phrase secrète de cryptage
  var hmac = new HMACSHA256();
  var cle = Convert.ToBase64String(hmac.Key);
  try
  {
    var tokenHandler = new JwtSecurityTokenHandler();
    var jwtJeton = tokenHandler.ReadToken(jeton) as JwtSecurityToken;
    if (jwtJeton == null)
      return null;
    var validationParameters = new TokenValidationParameters()
    {
      RequireExpirationTime = true,
      ValidateIssuer = false,
      ValidateAudience = false,
      IssuerSigningKey = new SymmetricSecurityKey(cle)
    };
    SecurityToken jetonSecurite;
     var information = tokenHandler.ValidateToken(jeton, validationParameters, out jetonSecurite);              
     return information;
   }
   catch (Exception)
   {
    //Gestion en cas d'erreur d'authentification 
    return null;
  }
}

La dernière fonction appelle la précédente pour récupérer le nom de l'utilisateur et la date d'expiration puis effectue les contrôles nécessaires pour autoriser ou non la connexion.

private static bool ValiderJeton(string jeton, out string nomUtilisateur)
{
  nomUtilisateur = null;
  //Appel de la fonction précédente pour récupérer l'information de connexion
  var simplePrinciple = JwtManager.GetPrincipal(jeton);
  var identity = simplePrinciple.Identity as ClaimsIdentity;
  if (identity == null)
    return false;
  if (!identity.IsAuthenticated)
    return false;
  var utilisateur = identity.FindFirst(ClaimTypes.Name);
  nomUtilisateur = usernameClaim.Value;
  if (string.IsNullOrEmpty(username))
   return false;
  // Action de contrôles supplémentaires (rôles, délai d'expiration…)
  return true;
}

JavaScript