web-dev-qa-db-fra.com

Authentification Dotnet Core 2.0 Cookies d'identité de schémas multiples et jwt

Dans dotnet core 1.1 asp, j'ai pu configurer et utiliser le middleware d'identité suivi du middleware jwt en procédant comme suit:

  app.UseIdentity();
  app.UseJwtBearerAuthentication(new JwtBearerOptions() {});

Cela a maintenant changé en ce sens que nous implémentons le middleware avec:

   app.UseAuthentication();

La configuration des paramètres est effectuée via la section ConfigureServices de Startup.cs.

Il existe certaines références à l'utilisation de schémas d'autorisation dans la documentation de migration:

https://docs.Microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x#authentication-middleware-and-services

Dans les projets 2.0, l'authentification est configurée via des services. Chaque Le schéma d'authentification est enregistré dans la méthode ConfigureServices de Startup.cs. La méthode UseIdentity est remplacée par UseAuthentication.

En outre, il est fait référence à:

Définition de schémas d'authentification par défaut

Dans 1.x, les propriétés AutomaticAuthenticate et AutomaticChallenge étaient destinés à être définis sur un schéma d'authentification unique. Il y avait pas un bon moyen de faire respecter cela. 

En 2.0, ces deux propriétés ont été supprimé en tant qu'indicateurs sur chaque instance AuthenticationOptions et ont déménagé dans la classe AuthenticationOptions de base. Les propriétés peut être configuré dans l'appel de méthode AddAuthentication dans le fichier Méthode ConfigureServices de Startup.cs:

Vous pouvez également utiliser une version surchargée de AddAuthentication méthode pour définir plusieurs propriétés. Dans ce qui suit surchargé exemple de méthode, le schéma par défaut est défini sur CookieAuthenticationDefaults.AuthenticationScheme. L'authentification Ce schéma peut également être spécifié au sein de votre personne [Autoriser] attributs ou politiques d'autorisation.

Est-il toujours possible dans Dotnet Core 2.0 d'utiliser plusieurs schémas d'authentification? Je ne parviens pas à faire en sorte que la politique respecte la configuration de JWT (schéma "Bearer") et seule Identity fonctionne actuellement, les deux étant configurés. Je ne trouve aucun exemple de plusieurs schémas d'authentification.

Modifier:

J'ai relu la documentation et comprends maintenant que le:

app.UseAuthentication()

ajoute une authentification automatique à un schéma par défaut. Identity configure les schémas par défaut pour vous.

J'ai contourné le problème avec ce qui semble être un bidouillage allant à l'encontre des nouvelles API en procédant comme suit dans Startup.cs Configurez:

    app.UseAuthentication();
    app.Use(async (context, next) =>
    {
        if (!context.User.Identity.IsAuthenticated)
        {
            var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
            if (result?.Principal != null)
            {
                context.User = result.Principal;
            }
        }

        await next.Invoke();
    });

Est-ce la bonne façon de faire ou devrais-je utiliser le framework, l'ID et les interfaces pour les implémentations personnalisées de IAuthenticationSchemeProvider?

Edit - Plus de détails sur l'implémentation et où le trouver.

La configuration de JWT peut être trouvée ici, et j'utilise des politiques pour définir l'autorisation, qui incluent les schémas d'authentification acceptés:

https://github.com/Arragro/ArragroCMS/blob/master/src/ArragroCMS.Management/Startup.cs

Le middleware personnalisé est toujours implémenté. Le contrôleur Auth est ici:

https://github.com/Arragro/ArragroCMS/blob/master/src/ArragroCMS.Web.Management/ApiControllers/AuthController.cs

Il utilise des clés API générées par l'application pour obtenir un accès en lecture seule aux données. Vous pouvez trouver l'implémentation d'un contrôleur utilisant la politique ici:

https://github.com/Arragro/ArragroCMS/blob/master/src/ArragroCMS.Web.Management/ApiControllers/SitemapController.cs

Modifiez la chaîne de connexion à la base de données pour qu'elle pointe vers votre serveur SQL, puis exécutez l'application. Il migre automatiquement la base de données et configure un utilisateur administrateur ([email protected] - ArragroPassword1!). Ensuite, allez à l'onglet Paramètres dans la barre de menu et cliquez sur "Configurer les paramètres de clé de l'API JWT ReadOnly" pour obtenir une clé. Dans Postman, obtenez un jeton JWT en configurant un nouvel onglet et en le configurant sur POST avec l'adresse suivante:

http: // localhost: 5000/api/auth/readonly-token

Fournissez les en-têtes: Content-Type: application/json

Fournir le corps: 

{
    "apiKey": "the api token from the previous step"
}

Copiez le jeton dans la réponse, puis utilisez ce qui suit dans postman:

http: // localhost: 5000/api/plan du site/flat

Authorization: "bearer - The token you received in the previous request"

Cela fonctionnera initialement à cause du middleware personnalisé. Commentez le code mentionné ci-dessus et essayez à nouveau et vous recevrez un 401.

Edit - @ La réponse de DonnyTian ci-dessous couvre ma solution dans ses commentaires. Le problème que je rencontrais était de définir une politique par défaut sur UseMvc, mais de ne pas fournir le schéma:

    services.AddMvc(config =>
    {
        var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme })
                         .RequireAuthenticatedUser()
                         .Build();
        config.Filters.Add(new AuthorizeFilter(defaultPolicy));
        config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
        config.Filters.Add(new ValidateModelAttribute());
    });

En suivant les conseils, cela fonctionne sans middleware personnalisé.

26
didiHamman

Asp.Net Core 2.0 prend définitivement en charge plusieurs schémas d'authentification . Plutôt qu'un piratage avec un middleware d'authentification, vous pouvez essayer de spécifier le schéma dans l'attribut Authorize:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

J'ai essayé et cela a bien fonctionné. En supposant que vous ayez ajouté à la fois Identity et JWT comme ci-dessous:

services.AddIdentity<ApplicationUser, ApplicationRole>()
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

Puisque AddIdentity() a déjà défini l'authentification par cookie comme schéma par défaut, nous devons spécifier le schéma dans l'attribut Authorize des contrôleurs. Pour l'instant, je ne sais pas comment écraser le schéma par défaut défini par AddIdentity(), ou peut-être ferions-nous mieux de ne pas le faire.

Une solution consiste à composer une nouvelle classe (vous pouvez l’appeler JwtAuthorize) qui dérive de Authorize et dont le schéma par défaut est Bearer . Vous n’avez donc pas à le spécifier à chaque fois.

METTRE &AGRAVE; JOUR

Trouver le moyen de remplacer le schéma d'authentification par défaut d'Identity!

Au lieu de la ligne ci-dessous:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)

Utilisez la surcharge ci-dessous pour définir le schéma par défaut:

services.AddAuthentication(option =>
                {
                    option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(options =>....

UPDATE 2 Comme indiqué dans les commentaires, vous pouvez activer les autorisations Identity et JWT en les joignant ensemble . [Authorize(AuthenticationSchemes = "Identity.Application" + "," + JwtBearerDefaults.AuthenticationScheme)]

21
DonnyTian

J'ai utilisé cette question pour résoudre mon problème (similaire) de combinaison de l'authentification d'identité et du porteur dans une application Web .Net Core 2.0. Il est important de noter que vous devez ajouter new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme au code suivant: 

services.AddMvc(config =>
    {
        var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme })
                         .RequireAuthenticatedUser()
                         .Build();
        config.Filters.Add(new AuthorizeFilter(defaultPolicy));
        config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
        config.Filters.Add(new ValidateModelAttribute());
    });

ET

Ajoutez l'option d'authentification par défaut: 

services.AddAuthentication(option =>
                {
                    option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                })
                .AddJwtBearer(options =>....

Dans ma solution initiale basée sur cette question, je n'ai pas remarqué que les deux modifications de mon code étaient nécessaires. J'espère pouvoir sauver à quelqu'un les heures que j'ai perdues :)

13
MartinH

Sean Wildermuth a publié un article sur l'activation des cookies et de jwt: https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-AS-Net-Core-2

Il l'enchaine comme ceci:

services.AddAuthentication()
  .AddCookie(cfg => cfg.SlidingExpiration = true)
  .AddJwtBearer(cfg =>
  {
    cfg.RequireHttpsMetadata = false;
    cfg.SaveToken = true;

    cfg.TokenValidationParameters = new TokenValidationParameters()
    {
      ValidIssuer = Configuration["Tokens:Issuer"],
      ValidAudience = Configuration["Tokens:Issuer"],
      IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
    };

  });
0
Guerrilla

D'après ce que dit kevin rich ici/ http://www.whoiskevinrich.com/configuring-asp-net-core-2-0-authentication

J'ai pu définir jwt comme méthode d'authentification par défaut:

        services.AddAuthentication(sharedOptions =>
        {
            sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            sharedOptions.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;
        })

J'ai testé cela et j'ai pu supprimer (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme) de l'attribut authorize mentionné dans le message de donnytian.

0
John