web-dev-qa-db-fra.com

Middleware d'authentification ASP.NET Core 2.0

Avec le noyau 1.1 suivi les conseils de @ blowdart et mis en place un middleware personnalisé:

https://stackoverflow.com/a/31465227/29821

Cela a fonctionné comme ceci:

  1. Middleware a couru. Ramassé un jeton à partir des en-têtes de demande.
  2. Vérifié le jeton et, s'il est valide, construit une identité (ClaimsIdentity) contenant plusieurs revendications, qu'il a ensuite ajoutée via HttpContext.User.AddIdentity ();
  3. Dans ConfigureServices using services.AddAuthorization, j'ai ajouté une stratégie pour exiger la revendication fournie par le middleware.
  4. Dans les contrôleurs/actions, j'utiliserais ensuite [Authorize (Roles = "un rôle ajouté par le middleware")]

Cela fonctionne un peu avec la version 2.0, sauf que si le jeton n'est pas valide (étape 2 ci-dessus) et que la revendication n'est jamais ajoutée, j'obtiens "Aucun authenticationScheme n'a été spécifié et aucun DefaultChallengeScheme n'a été trouvé."

Alors maintenant, je lis que l'auth a changé en 2.0:

https://docs.Microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x

Quel est le bon chemin pour moi de faire la même chose dans ASP.NET Core 2.0? Je ne vois pas d'exemple pour faire une authentification vraiment personnalisée.

78
pbz

Ainsi, après une longue journée d’essais pour résoudre ce problème, j’ai enfin compris comment Microsoft souhaitait que nous créions des gestionnaires d’authentification personnalisés pour sa nouvelle configuration à un seul middleware dans le noyau 2.0.

Après avoir parcouru une partie de la documentation sur MSDN, j'ai trouvé une classe appelée AuthenticationHandler<TOption> qui implémente l'interface IAuthenticationHandler.

À partir de là, j'ai trouvé une base de code complète avec les schémas d'authentification existants situés à l'emplacement https://github.com/aspnet/Security

À l'intérieur de l'un d'entre eux, il montre comment Microsoft implémente le schéma d'authentification JwtBearer. ( https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer )

J'ai copié la majeure partie de ce code dans un nouveau dossier et effacé tout ce qui avait trait à JwtBearer.

Dans la classe JwtBearerHandler (qui étend AuthenticationHandler<>), il existe un remplacement pour Task<AuthenticateResult> HandleAuthenticateAsync()

J'ai ajouté dans notre ancien middleware la configuration des revendications via un serveur de jetons personnalisé et je rencontrais toujours des problèmes d'autorisations. Je crachais simplement un 200 OK au lieu d'un 401 Unauthorized lorsqu'un jeton était invalide et qu'aucune revendication ont été mis en place.

J'ai réalisé que j'avais remplacé Task HandleChallengeAsync(AuthenticationProperties properties) qui, pour une raison quelconque, est utilisé pour définir des autorisations via [Authorize(Roles="")] dans un contrôleur.

Après avoir supprimé cette substitution, le code avait fonctionné et avait lancé avec succès un 401 lorsque les autorisations ne correspondaient pas.

La principale conséquence de ceci est que, maintenant, vous ne pouvez plus utiliser d'intergiciel personnalisé, vous devez l'implémenter via AuthenticationHandler<> et vous devez définir les paramètres DefaultAuthenticateScheme et DefaultChallengeScheme lorsque vous utilisez services.AddAuthentication(...).

Voici un exemple de ce à quoi tout devrait ressembler:

Dans Startup.cs/ConfigureServices (), ajoutez:

services.AddAuthentication(options =>
{
    // the scheme name has to match the value we're going to use in AuthenticationBuilder.AddScheme(...)
    options.DefaultAuthenticateScheme = "Custom Scheme";
    options.DefaultChallengeScheme = "Custom Scheme";
})
.AddCustomAuth(o => { });

Dans Startup.cs/Configure (), ajoutez:

app.UseAuthentication();

Créer un nouveau fichier CustomAuthExtensions.cs

public static class CustomAuthExtensions
{
    public static AuthenticationBuilder AddCustomAuth(this AuthenticationBuilder builder, Action<CustomAuthOptions> configureOptions)
    {
        return builder.AddScheme<CustomAuthOptions, CustomAuthHandler>("Custom Scheme", "Custom Auth", configureOptions);
    }
}

Créer un nouveau fichier CustomAuthOptions.cs

public class CustomAuthOptions: AuthenticationSchemeOptions
{
    public CustomAuthOptions()
    {

    }
}

Créer un nouveau fichier CustomAuthHandler.cs

internal class CustomAuthHandler : AuthenticationHandler<CustomAuthOptions>
{
    public CustomAuthHandler(IOptionsMonitor<CustomAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
    {
        // store custom services here...
    }
    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // build the claims and put them in "Context"; you need to import the Microsoft.AspNetCore.Authentication package
        return AuthenticateResult.NoResult();
    }
}
174
Zac

Comme le souligne l'article cité en référence, Identity passe de Core 1.x à Core 2.0. Le changement majeur consiste à abandonner l’approche middleware et à utiliser l’injection de dépendance pour configurer des services personnalisés. Cela offre beaucoup plus de flexibilité dans la personnalisation d'Identity pour des implémentations plus complexes. Vous voulez donc vous éloigner de l’approche middleware que vous avez mentionnée ci-dessus et évoluer vers les services. Suivez les étapes de migration de l'article référencé pour atteindre cet objectif. Commencez par remplacer app.UseIdentity par app.UseAuthentication . UseIdentity est amorti et ne sera plus pris en charge dans les versions futures. Pour obtenir un exemple complet de la procédure à suivre pour insérer une transformation de revendications personnalisée et effectuer une autorisation sur la revendication: voir cet article de blog .

4
Kevin Junghans