Aller au contenu principal

18-1 Claims et ClaimsFactory

Identity fait usage du concept de Claims pour gérer des propriétés supplémentaires associées à l'utilisateur.

Il faut voir le terme Claims un peu comme quelque chose que l'utilisateur s'est approprié. La traduction la plus directe serait une revendication. Les claims permettent de décrire ce qu'un utilisateur est:

  • Id
  • Nom
  • Prenom
  • Courriel
  • Role
  • ...

Ces claims se retrouvent dans le cookie contenant certains détails de l'utilisateur et qui est récupéré à chaque requête par le serveur.

Par défaut, seulement le nom d'utilisateur de l'usager (le courriel dans notre cas) se trouve dans la liste de Claims.

Pour ajouter des Claims, il faudra créer une classe héritant de UserClaimsPrincipalFactory et réimplémenter la fonction responsable de générer les claims, soit GenerateClaimsAsync.

Créer une classe UserClaimsPrincipalFactory

La classe UserClaimsPrincipalFactory sera responsable de générer les Claims.

Comme il s'agit d'une implémentation propre à la logique de notre application, nous la mettrons dans le projet Application. Le meilleur endroit est cependant ouvert à interprétation.

  1. Créer un dossier Claims. Sous le projet Application, ajoutez un dossier nommé Claims.
  2. Créer la classe. Sous le nouveau dossier Snowfall.Application/Claims, ajoutez une classe nommée ApplicationClaimsPrincipalFactory.cs
  3. Code de base. Pour débuter, vous pouvez mettre ceci dans la classe:
    Snowfall.Application/Claims/ApplicationClaimsPrincipalFactory.cs
    using System.Security.Claims;
    using Microsoft.AspNetCore.Identity;
    using Microsoft.Extensions.Options;
    using Snowfall.Domain.Models;

    namespace Snowfall.Application.Claims;

    /// <summary>
    /// Permets de générer les attributs de l'utilisateur (Claims) étant accessibles sans faire de requête
    /// à la BD. Ces claims sont donc stockés dans un cookie, par exemple (en mode rendu serveur), et récupérés
    /// par le serveur à chaque requête.
    /// </summary>
    public class ApplicationClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
    {
    public ApplicationClaimsPrincipalFactory(
    UserManager<ApplicationUser> userManager,
    RoleManager<ApplicationRole> roleManager,
    IOptions<IdentityOptions> options)
    : base(userManager, roleManager, options)
    {
    }

    /// <summary>
    /// Génère les claims propres à l'application. Cette méthode 'override' celle de
    /// UserClaimsPrincipalFactory. C'est pourquoi on appel base.GenerateClaimsAsync()
    /// dans un premier temps.
    /// </summary>
    /// <param name="user"></param>
    /// <returns></returns>
    protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
    ClaimsIdentity claims = await base.GenerateClaimsAsync(user);

    return claims;
    }
    }
À propos de la classe
  • public class ApplicationClaimsPrincipalFactory crée une classe qui hérite de UserClaimsPrincipalFactory, soit la classe de .NET Core responsable de générer les claims.
  • protected override async Task<ClaimsIdentity> GenerateClaimsAsync réimplémente la fonction responsable de générer les claims pour un utilisateur
  • ClaimsIdentity claims = await base.GenerateClaimsAsync(user); pour conserver le comportement de base de la fonction, on peut appeler la même fonction que nous sommes en train de réimplémenter, mais sur base, soit la classe parent

Ajouter des Claims (attributs de l'utilisateur)

On peut ensuite ajouter différents attributs à la liste de Claims, via AddClaim de la façon suivante.

Snowfall.Application/Claims/ApplicationClaimsPrincipalFactory.cs
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
{
ClaimsIdentity claims = await base.GenerateClaimsAsync(user);

claims.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id!));
claims.AddClaim(new Claim(ClaimTypes.GivenName, user.Prenom));
claims.AddClaim(new Claim(ClaimTypes.Surname, user.Nom));
claims.AddClaim(new Claim("NomComplet", $"{user.Prenom} {user.Nom}"));

return claims;
}
info

Certains types prédéfinis sont disponibles, comme ClaimTypes.NameIdentifier ou encore ClaimTypes.GivenName, mais on peut aussi leur donner un nom personnalisé comme dans l'exemple "NomComplet".

Au fond, le premier paramètre est seulement un string, qu'il s'agisse d'un d'un claim prédéfini ou nom.

Ainsi, dans notre cas, on ajoute les claims suivants:

  • NameIdentifier le ID de l'utilisateur
  • GivenName le prénom de l'utilisateur
  • Surname le nom de l'utilisateur
  • NomComplet le nom complet de l'utilisateur