Intergiciel d'authentification ASP.NET Core 2.0

89

Avec Core 1.1, suivez les conseils de @ blowdart et implémentez un middleware personnalisé:

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

Cela a fonctionné comme ceci:

  1. L'intergiciel a fonctionné. Ramassé un jeton dans les en-têtes de la demande.
  2. Vérifié le jeton et s'il est valide, construit une identité (ClaimsIdentity) qui contenait plusieurs revendications qu'il a ensuite ajoutées 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 alors [Authorize (Roles = "some role that the middleware added")]

Cela fonctionne quelque 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'authentification 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 pour faire la même chose dans ASP.NET Core 2.0? Je ne vois pas d'exemple pour faire une authentification vraiment personnalisée.

pbz
la source
Essayez ce lien, même s'il dit 2 schémas, mais cela vous donnerait un avertissement
Mithun Pattankar
pouvez-vous ajouter votre code pour que nous puissions jeter un œil? Je sais que j'ai eu des problèmes avec JWT dans core2.0 - c'était un cas de le déplacer dans le démarrage
Webezine

Réponses:

193

Ainsi, après une longue journée à essayer de résoudre ce problème, j'ai enfin compris comment Microsoft veut que nous créions des gestionnaires d'authentification personnalisés pour leur nouvelle configuration de middleware unique 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' IAuthenticationHandlerinterface.

À partir de là, j'ai trouvé une base de code entière avec les schémas d'authentification existants situés à 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 plupart de ce code dans un nouveau dossier et effacé tout ce qui s'y rapporte JwtBearer.

Dans la JwtBearerHandlerclasse (qui s'étend AuthenticationHandler<>), il y a un remplacement pourTask<AuthenticateResult> HandleAuthenticateAsync()

J'ai ajouté notre ancien middleware pour la configuration des revendications via un serveur de jetons personnalisé, et je rencontrais toujours des problèmes avec les autorisations, crachant simplement un 200 OKau lieu d'un 401 Unauthorizedlorsqu'un jeton était invalide et qu'aucune revendication n'était configurée.

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

Après avoir supprimé ce remplacement, le code avait fonctionné et avait réussi à lancer un 401lorsque les autorisations ne correspondaient pas.

Le principal à retenir est que vous ne pouvez plus utiliser d'intergiciel personnalisé, vous devez l'implémenter via AuthenticationHandler<>et vous devez définir le DefaultAuthenticateSchemeet DefaultChallengeSchemelors de l'utilisation services.AddAuthentication(...).

Voici un exemple de ce à quoi tout cela 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();
    }
}
Zac
la source
1
excellent article, mais j'ai quelques problèmes pour compiler votre code. Les types CustomAuthOptions et AuthenticateResult sont manquants. Pourriez-vous les publier?
alexb
8
Êtes-vous prêt à partager vos conclusions sous forme de code sur un dépôt Github?
CSharper
2
Pourriez-vous s'il vous plaît expliquer DefaultAuthenticateSchemeet DefaultChallengeScheme? Je ne comprends pas pourquoi ils sont tous les deux utilisés? et quelles sont les différences entre eux.
Mohammed Noureldin
10
+1 pour "À partir de là, j'ai trouvé une base de code entière avec les schémas d'authentification existants situés sur github.com/aspnet/Security ." Regardez simplement comment l'équipe ASP.NET le fait en suivant cette réponse (vraiment excellente). L'un de nous a-t-il jamais pensé qu'un jour nous poserions des questions sur le code et les pratiques de la SEP et que la réponse serait: "Jetez un œil à leur base de code?"
Marc L.
3
Pour les autres qui arrivent plus tard, vous devez AuthExtensionêtre à l'intérieur de l' Microsoft.Extensions.DependencyInjectionespace de noms. Voir cet exemple: github.com/aspnet/Security/blob/rel/2.0.0/src/…
Garry Polley
4

Il y a des changements considérables dans l'identité de Core 1.x à Core 2.0 comme le souligne l'article que vous référencez. Le changement majeur consiste à s'éloigner de l'approche middleware et à utiliser l'injection de dépendances pour configurer des services personnalisés. Cela offre beaucoup plus de flexibilité dans la personnalisation de l'identité pour des implémentations plus complexes. Vous souhaitez donc vous éloigner de l'approche middleware que vous avez mentionnée ci-dessus et vous diriger 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 déprécié et ne sera plus pris en charge dans les versions futures. Pour un exemple complet de la façon d'insérer une transformation de revendication personnalisée et d'exécuter une autorisation sur la revendicationvoir ce billet de blog .

Kevin Junghans
la source
12
Existe-t-il un exemple sur la façon de l'utiliser avec une application WebAPI?
alexb le