web-dev-qa-db-fra.com

La validation JWT d'ASP.NET Core 2.0 échoue avec l'erreur `L'autorisation a échoué pour l'utilisateur: (null)`

J'utilise l'application ASP.NET Core 2.0 (Web API) en tant qu'émetteur JWT pour générer un consommable de jeton par une application mobile. Malheureusement, ce jeton n'a pas pu être validé par un contrôleur alors qu'il peut l'être par un autre (en utilisant le même paramètre de validation dans la même application asp.net core 2.0).

Donc, j'ai un jeton qui est valide et qui pourrait être décodé, a toutes les revendications requises et les horodatages. Mais un point de terminaison l'accepte, tandis qu'un autre me donne une erreur 401 et une sortie de débogage: 

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: L'autorisation a échoué pour l'utilisateur: (null).

[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed for user: (null).
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
      Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
      Executing ChallengeResult with authentication schemes ().
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
      AuthenticationScheme: Bearer was challenged.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: Bearer was challenged.
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
      Executed action MyController.Get (WebApi) in 72.105ms
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action MyController.Get (WebApi) in 72.105ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 271.077ms 401 
[40m[32minfo[39m[22m[49m: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
      Request finished in 271.077ms 401 

Ma configuration de validation est ci-dessous:

var secretKey = Configuration["Authentication:OAuth:IssuerSigningKey"];
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));
var tokenValidationParameters = new TokenValidationParameters
{
   ValidateIssuerSigningKey = true,
   IssuerSigningKey = signingKey,
   ValidateIssuer = true,
   ValidIssuer = Configuration["Authentication:OAuth:Issuer"],
   ValidateAudience = true,
   ValidAudience = Configuration["Authentication:OAuth:Audience"],
   ValidateLifetime = true,
   ClockSkew = TimeSpan.Zero,
};

services.AddAuthentication(options =>
{
   options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
   options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
   options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = tokenValidationParameters;
});

Ces deux points d'extrémité sont identiques. Ils résident simplement dans des contrôleurs différents, tous deux marqués avec l'attribut Authorize.

Comment est-ce possible?

25
Alexey Strakh

La séquence des instructions add dans la fonction configure est importante. Sois sûr que

app.UseAuthentication();

vient avant 

app.UseMvc();

Est-ce que cela pourrait être le problème?

46
Ole Lindstad

Dans votre méthode startup.cs ConfigureServices si vous ajoutez

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

Explication: Lorsque vous utilisez [Authorize] sur un contrôleur, il se lie par défaut au premier système d'autorisation. 

options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

Avec cela, vous définissez par défaut l'authentification JWT Bearer.

en plus vous pouvez ajouter 

options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

cette ligne explique comment éviter d'obtenir des erreurs 404 non trouvées lors de l'utilisation d'Identity with JWT. Si vous utilisez identité, DefaultChallengeScheme essaiera de vous rediriger vers une page de connexion, ce qui, s'il n'existe pas, aura pour résultat un 404 non trouvé plutôt que le 401 non autorisé souhaité. en définissant le DefaultChallengeScheme sur JwtBearerDefaults.AuthenticationScheme sur non autorisé, il ne tentera plus de vous rediriger vers une page de connexion.

Si vous utilisez l'authentification par cookie avec l'authentification JWT dans la balise [Autoriser] , vous pouvez spécifier le schéma d'authentification de votre choix. par exemple

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
8
Kevin

J'ai ajouté:

app.UseAuthentication();

Dans Startup.Configure() et qui a résolu cette erreur pour moi.

Référence: Annonce de migration Auth 2.0

3
spottedmahn

essayez ceci dans startup.cs

services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        }).AddJwtBearer(opts => ...
2
user1508188

Quand des authentifications sont ajoutées comme:

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

Cela signifie que chaque attribut [Authorize] placé au-dessus d'une méthode ou d'une classe de contrôleur essaiera de s'authentifier selon le schéma d'authentification par défaut (dans ce cas, JwtBearer) ET CE N'EST PAS ABATTU to essayez de vous authentifier auprès d'autres schémas pouvant être déclarés (comme le schéma Cookie). Afin de permettre l’authentification de AuthorizeAttribute par rapport au schéma de cookie, elle doit être spécifiée comme suit: 

[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]

Cela fonctionnera également dans l'autre sens, c'est-à-dire si le schéma de cookie est défini par défaut, le schéma JwtBearer doit être déclaré pour l'autorisation des méthodes ou des contrôleurs nécessitant une authentification par jeton JwtBearer.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
0
theCuriousOne

Vérifiez le codage de la clé de signature dans votre fournisseur de jetons, par exemple UTF8 et non ASCII.

0
H.Wojtowicz

Cela semble être le comportement que vous recevez lorsque votre JWT n'est pas validé correctement. J'ai eu ce problème à la suite de taper "porteur: (JWT)" au lieu de "porteur (JWT)" dans l'en-tête

0
Jon B