Проверка JWT в ASP.NET Core 2.0 завершается неудачно с ошибкой «Авторизация не удалась для пользователя: (null)»

Я использую приложение ASP.NET Core 2.0 (веб-API) в качестве эмитента JWT для создания токена, потребляемого мобильным приложением. К сожалению, этот токен не может быть проверен одним контроллером, но может быть проверен другим (с использованием той же настройки проверки в том же приложении asp.net core 2.0).

Итак, у меня есть токен, который действителен и может быть декодирован, имеет все необходимые утверждения и временные метки. Но одна конечная точка принимает это, а другая выдает мне ошибку 401 и вывод отладки:

Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: информация: не удалось выполнить авторизацию для пользователя: (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 

Моя настройка проверки ниже:

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;
});

Эти две конечные точки идентичны, просто находятся в разных контроллерах, оба отмечены атрибутом Authorize.

Как такое возможно?


person Alexey Strakh    schedule 22.08.2017    source источник
comment
+1 Ваш подробный код привлек мое внимание к ClockSkew, что позволило мне понять отдельную проблему, в которой срок действия моих токенов не истек.   -  person ne1410s    schedule 06.09.2018


Ответы (11)


Последовательность операторов добавления в функции настройки имеет значение. Убедись в том, что

app.UseAuthentication();

приходит раньше

app.UseMvc();

Может быть, в этом проблема?

person Ole Lindstad    schedule 23.10.2017
comment
В моем случае первоначальный запрос к операции, украшенной атрибутом Authorize, будет успешным, а затем все последующие запросы не будут выполнены. Это устранило мою проблему. - person 6footunder; 20.03.2019
comment
Мне стыдно сказать, что мне не хватало app.UseAuthentication (); полностью! - person ben_mj; 08.04.2019
comment
Забудьте про порядок, совсем забыл поставить часть app.UseAthentication (). Спасибо, Оле. - person Hari Krishna Gaddipati; 29.08.2019
comment
Я знал, что этот порядок имеет значение, но я все еще не думал, что аутентификация должна предшествовать MVC .... да. Спасибо! - person Zachary Hale; 15.09.2019
comment
Может кто-нибудь объяснить, почему порядок имеет значение. - person user1843640; 30.09.2019

Для Dotnetcore 3.1 я поместил app.UseAuthentication() перед app.UseAuthorization()

person jayasurya_j    schedule 16.03.2020
comment
Если бы я мог дать этому 1000 голосов, я бы это сделал. Если есть такая необходимость в заказе этих вещей, можно подумать, что будет предупреждение. - person Dale Francis; 07.06.2020

В методе ConfigureServices startup.cs, если вы добавите

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

Объяснение: Когда вы используете [Авторизовать] на контроллере, он по умолчанию привязывается к первой системе авторизации.

options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;

При этом вы устанавливаете по умолчанию аутентификацию на предъявителя JWT.

дополнительно вы можете добавить

options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

в этой строке рассказывается, как предотвратить получение ошибки 404 not found при использовании Identity с JWT. Если вы используете идентификацию, DefaultChallengeScheme попытается перенаправить вас на страницу входа в систему, что, если она не существует, приведет к получению 404 не найденного, а не желаемого 401 неавторизованного. установив для DefaultChallengeScheme значение JwtBearerDefaults.AuthenticationScheme при несанкционированном доступе, он больше не будет пытаться перенаправить вас на страницу входа

Если вы используете аутентификацию с помощью файлов cookie с аутентификацией JWT, в теге [Authorize] вы можете указать, какую схему аутентификации вы хотите. Например

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
person Kevin    schedule 20.02.2018
comment
можете ли вы объяснить, что здесь происходит: stackoverflow.com/questions/51263883. Моя работает только с [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] - person ahmad molaie; 10.07.2018

Для всех, кто использует .NET Core 3.1, это работает следующим образом:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseCors("AllowOrigin");
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}
person Martin Brandl    schedule 17.03.2020

Я добавил:

app.UseAuthentication();

В Startup.Configure(), и это решило эту ошибку для меня.

Ссылка: Объявление о переходе на Auth 2.0

person spottedmahn    schedule 20.10.2017

Когда добавляются аутентификации, например:

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

Это означает, что каждый атрибут [Authorize], который помещается поверх метода или класса контроллера, будет пытаться аутентифицироваться по схеме аутентификации по умолчанию (в данном случае JwtBearer) И ЭТО НЕ БУДЕТ КАСКАДНО ВНИЗ чтобы попытаться аутентифицироваться с помощью других схем, которые могут быть объявлены (например, схемы Cookie). Чтобы авторизовать AuthorizeAttribute по схеме cookie, он должен быть указан как

[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]

Это будет работать и в обратном направлении, т.е. если по умолчанию используется схема cookie, тогда необходимо объявить схему JwtBearer для авторизации для тех методов или контроллеров, которым потребуется аутентификация токена JwtBearer.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
person theCuriousOne    schedule 07.11.2018

попробуйте это в startup.cs

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

Это похоже на поведение, которое вы получаете, когда ваш JWT не проверяется правильно. У меня возникла эта проблема из-за того, что я набрал "Bearer: (JWT)" вместо "Bearer (JWT)" в заголовке.

person Jon B    schedule 10.02.2018

Если кому-то не повезло с ответами, касающимися конфигурации IServiceCollection.AddAuthentication или реализации Startup.Configure, вы можете попробовать изменить конфигурацию IServiceCollection.AddAuthorization.

Перед внесением этого изменения вызовы API с правильным токеном завершились ошибкой со следующими строками журнала.

[Information] [Microsoft.AspNetCore.Hosting.Diagnostics] Request starting HTTP/1.1 POST http://localhost:5000/api application/json 18
[Debug] [Microsoft.AspNetCore.Routing.Matching.DfaMatcher] 1 candidate(s) found for the request path '"/api"'
[Debug] [Microsoft.AspNetCore.Routing.Matching.DfaMatcher] Endpoint '"ApplicationNamespace.Controllers.ApiController.CreateAsync (ApplicationNamespace)"' with route pattern '"Api"' is valid for the request path '"/api"'
[Debug] [Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware] Request matched endpoint '"ApplicationNamespace.Controllers.ApiController.CreateAsync (ApplicationNamespace)"'
[Debug] [Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler] AuthenticationScheme: "Identity.Application" was not authenticated.
[Debug] [Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler] AuthenticationScheme: "Identity.Application" was not authenticated.
[Information] [Microsoft.AspNetCore.Authorization.DefaultAuthorizationService] Authorization failed.
[Information] [Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler] Successfully validated the token.
[Information] [Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler] AuthenticationScheme: "Bearer" was challenged.
[Information] [Serilog.AspNetCore.RequestLoggingMiddleware] HTTP "POST" "/api" responded 401 in 4.6311 ms

В Startup.ConfigureServices у меня это работает, когда я применил политику по умолчанию с указанной схемой аутентификации.

services.AddAuthorization(opt =>
  {
    var builder = new AuthorizationPolicyBuilder();
    builder.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
    builder.RequireAuthenticatedUser();
    opt.DefaultPolicy = builder.Build();
  });
person Alex Ho    schedule 30.10.2020

Проверьте кодировку ключа подписи в вашем провайдере токенов, это может быть, например, UTF8, а не ASCII.

person lissajous    schedule 22.12.2018

Вместо этого вы можете попробовать следующее:

.AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = tokenValidationParameters;
});'
person Ömer SÖNMEZ    schedule 22.08.2017
comment
Совершенно уверен, что это не сработает. Начиная с ядра 2.0, AutomaticAuthenticate и AutomaticChallenge удалены из JwtBearerOptions. прочтите здесь: docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/ - person Sunil Shahi; 23.08.2017
comment
да, он был удален, и теперь он заменен на defaultAuthenticateScheme и defaultChallengeScheme. - person Alexey Strakh; 23.08.2017