Authentification Forms et gestion de la connexion
L'authentification Forms active une connexion par login et mot de passe. Elle se configure côté serveur dans OnConfigureAuthentification.
Activer Forms
protected override void OnConfigureAuthentification(AuthenticationOptions options)
{
// Active la saisie login / mot de passe sur la page de connexion.
options.AllowFormAuthentication = true;
}
Forms peut être combiné avec Windows ou un fournisseur externe. Dans ce cas, la page de connexion détermine si elle doit rediriger l'utilisateur vers un fournisseur externe ou afficher le mot de passe Forms.
Workflow d'authentification
Lorsqu'un utilisateur tente de se connecter, l'application peut intervenir dans le fichier Main.cs du projet serveur.
| Étape | Méthode | Usage |
|---|---|---|
| Impersonation de développement | GetImpersonatedIdentity() | Simuler une identité en DEBUG uniquement. |
| Configuration du contexte | OnConfigureAuthenticationContext(AuthenticationContext context) | Définir AllowUnknownUser, IsEmailLogin ou les options de rôles personnalisés. |
| Résolution utilisateur | GetIdentityUserAsync(AuthenticationContext context) | Retrouver l'utilisateur à partir du contexte. À surcharger seulement pour des cas particuliers. |
| Utilisateur inconnu | OnUnknownUserAsync(AuthenticationContext context) | Créer ou refuser un utilisateur absent de la base. |
| Post-connexion | OnSignInAsync(AuthenticationContext context, ApplicationUser user) | Mettre à jour l'utilisateur, ses rôles, ses claims ou les choix de rôle. |
Par défaut, l'exemple Demo ne déclenche pas la création automatique pour Forms : AllowUnknownUser est positionné à false quand AuthenticationMode vaut Forms.
Configurer le contexte d'authentification
protected override void OnConfigureAuthenticationContext(AuthenticationContext context)
{
// Les utilisateurs inconnus ne sont acceptés que hors Forms.
context.AllowUnknownUser = context.IdentitySource.AuthenticationMode != AuthenticationMode.Forms;
// La recherche utilisateur se fait par UserName plutôt que par Email.
context.IsEmailLogin = false;
}
Les propriétés principales du contexte sont :
| Propriété | Description |
|---|---|
IdentitySource.AuthenticationMode | Mode de connexion : Forms, Windows ou SSO. |
IdentitySource.Claims | Claims fournis par le fournisseur d'identité, notamment en SSO. |
IdentitySource.SourceName | Nom de la source d'identité. |
IdentitySource.UserLogin | Login fourni par la source d'identité. |
AllowUnknownUser | Indique si OnUnknownUserAsync peut être appelé. |
IsEmailLogin | Indique si l'utilisateur est recherché par Email plutôt que par UserName. |
IsCustomRolesEnabled | Indique si les rôles doivent être remplacés par les rôles personnalisés du contexte. |
Impersonation en développement
GetImpersonatedIdentity() sert uniquement aux tests et au développement. La méthode doit rester protégée par #if DEBUG.
#if DEBUG
public override IdentitySource GetImpersonatedIdentity()
{
// Lit l'identité simulée depuis la configuration de développement.
return ImpersonatedIdentity.FromConfiguration(Configuration);
}
#endif
{
"Impersonate": {
"Enabled": true,
"Login": "admin",
"FirstName": "Admin",
"LastName": "Demo"
}
}
Gérer un utilisateur inconnu
OnUnknownUserAsync est appelée si aucun utilisateur n'est trouvé et si AllowUnknownUser l'autorise. Elle peut retourner un utilisateur créé par l'application ou null pour refuser la connexion.
protected override Task<ApplicationUser> OnUnknownUserAsync(AuthenticationContext context)
{
// L'application refuse la création automatique de l'utilisateur.
return Task.FromResult<ApplicationUser>(null);
}
Exemple de création à la connexion pour une identité non Forms :
protected override Task<ApplicationUser> OnUnknownUserAsync(AuthenticationContext context)
{
string userLogin = context.IdentitySource.UserLogin;
ApplicationUser user = new()
{
Email = userLogin,
UserName = userLogin,
EmailConfirmed = true
};
// Crée l'utilisateur avec un rôle applicatif.
return CreateUserAsync(user, Roles.User);
}
Gérer la post-connexion avec OnSignInAsync
OnSignInAsync est appelée lorsque l'utilisateur est connu. Elle permet notamment de mettre à jour les rôles issus d'un facteur externe ou d'ajouter des claims au jeton avec context.AddCustomClaim(...). Un claim utilisé par une policy du serveur doit être déclaré dans AuthenticationOptions.AccessTokenClaims : voir Policy fondée sur un claim personnalisé.
protected override Task OnSignInAsync(AuthenticationContext context, ApplicationUser user)
{
// Les rôles externes remplacent les rôles existants pendant la connexion.
context.IsCustomRolesEnabled = true;
context.AddCustomRoles(GetExternalRoles(context.IdentitySource.UserLogin));
return Task.CompletedTask;
}
private static IEnumerable<string> GetExternalRoles(string userLogin)
{
// Exemple pédagogique : remplacer par la source externe réelle de l'application.
return new[] { Roles.User.ToString(), Roles.Admin.ToString() };
}
AddCustomRole et AddCustomRoles nécessitent d'activer IsCustomRolesEnabled avant l'ajout. Si aucun rôle n'est disponible, la connexion échoue.
Choix de rôle ou de profil
Si l'utilisateur possède plusieurs rôles, l'application peut proposer un choix pendant le workflow.
protected override Task OnSignInAsync(AuthenticationContext context, ApplicationUser user)
{
// Propose les rôles disponibles à l'utilisateur connecté.
context.EnableGroupChoice<Roles>();
return Task.CompletedTask;
}
Il est aussi possible d'ajouter explicitement des choix regroupant des rôles.
protected override Task OnSignInAsync(AuthenticationContext context, ApplicationUser user)
{
// Propose des profils composés de rôles applicatifs.
context.AddRoleChoice("Admin & User", Roles.Admin.ToString(), Roles.User.ToString());
context.AddRoleChoice("Only Admin", Roles.Admin.ToString());
context.AddRoleChoice("Only User", Roles.User.ToString());
return Task.CompletedTask;
}
Retrouver l'utilisateur
Par défaut, Lagoon retrouve l'utilisateur avec FindByEmailAsync si IsEmailLogin est vrai, sinon avec FindByNameAsync. Ne surchargez GetIdentityUserAsync que pour un cas particulier, par exemple plusieurs comptes pour un même utilisateur avec une notion actif/inactif.