Ошибка авторизации токена .NET Core 2.2 JWT не возвращает HTTP 401 - PullRequest
0 голосов
/ 11 января 2019

У меня проблема с тем, как .NET Core обрабатывает аутентификацию JSON Web Token (JWT) в моей производственной среде. Я тестирую с помощью Почтальона. Если я вызываю мой API с действительным токеном, он работает нормально и возвращает ожидаемый ответ от конечной точки API. Однако, если срок действия токена истек, я не получаю ожидаемый HTTP 401. На самом деле я не получаю никакого ответа, он просто тихо терпит неудачу. Кажется, что-то в моей производственной конфигурации не работает. Если я проверю это в своей локальной среде разработки, у меня не возникнет проблем, и токены с истекшим сроком действия получат не авторизованный HTTP-ответ 401, как ожидалось.

Мое веб-приложение использует как аутентификацию куки-файлов для тех, кто выполняет вход через веб-сайт, так и аутентификацию JWT для тех, кто подключается к API. Вот конфигурация для аутентификации JWT. Это в Startup.cs. Это часть конфигурации JWT сервисов. Аутентификация. Проверка подлинности с помощью cookie-файлов устанавливается первой и является схемой проверки подлинности по умолчанию.

.AddJwtBearer(options =>{
options.RequireHttpsMetadata = !_hostingEnvironment.IsDevelopment();

options.TokenValidationParameters = new TokenValidationParameters
{
    ValidateIssuer = true,
    ValidateAudience = true,
    ValidateLifetime = true,
    ValidateIssuerSigningKey = true,

    ValidIssuer = Settings.Api.JwtBearer.TokenValidation.ValidIssuer,
    ValidAudience = Settings.Api.JwtBearer.TokenValidation.ValidAudience,
    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Settings.Api.JwtBearer.TokenValidation.IssuerSigningKey))
};

options.Events = new JwtBearerEvents()
{
    OnAuthenticationFailed = context =>
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        context.Response.ContentType = "application/json; charset=utf-8";
        var message = _hostingEnvironment.IsDevelopment() ? context.Exception.ToString() : "An error occurred processing your authentication.";
        var result = JsonConvert.SerializeObject(new { message });
        return context.Response.WriteAsync(result);
    }
};});

А вот другая соответствующая конфигурация в Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env){
if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler("/Error/Exception");

    app.UseStatusCodePagesWithReExecute("/Error/{0}");

    app.UseHsts();

    app.UseHttpsRedirection();
}

app.UseStaticFiles();

app.UseCors(Constants.Security.Cors.PolicyName);

app.UseAuthentication();

app.UseMvc(ConfigureRoutes);}

` Я много играл с настройкой Configure и тестировал ее на производстве, но я всегда получаю ответ, когда аутентификация токена заканчивается неудачей. Так как он хорошо работает в моей локальной среде разработки, это должно означать, что с моей производственной конфигурацией что-то не так, но я в замешательстве и без идей. Для получения дополнительной информации вот пример ошибки из журналов ошибок:

информация: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler [1] Не удалось проверить токен. Microsoft.IdentityModel.Tokens.SecurityTokenExpiredException: IDX10223: Проверка продолжительности жизни не удалась. Срок действия токена истек. Действителен до: '[PII скрыт]', Текущее время: '[PII скрыт]'. в Microsoft.IdentityModel.Tokens.Validators.ValidateLifetime (Nullable 1 notBefore, Nullable 1 истекает, SecurityToken securityToken, TokenValidationParameters validationParameters) в System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateLifetime (Nullable 1 notBefore, Nullable 1 истекает, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters) в System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload (JwtSecurityToken jwtToken, TokenValidationParameters validationParameters) в System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken (String токен, TokenValidationParameters validationParameters, SecurityToken & validatedToken) в Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__6.MoveNext () Информация: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler [7] Носитель не был аутентифицирован. Сообщение об ошибке: IDX10223: проверка срока службы не удалась. Срок действия токена истек. ValidTo: '[PII является скрытый] ', Текущее время:' [PII скрыт] '. Информация: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService [2] Авторизация не удалась. информация: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker [3] Авторизация не выполнена для запроса в фильтре «Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter». Информация: Microsoft.AspNetCore.Mvc.ChallengeResult [1] Выполнение ChallengeResult со схемами аутентификации (Bearer). информация: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker [2] Выполнено действие Web.Controllers.ApiController.Users (Web) в 109.4625ms информация: Microsoft.AspNetCore.Routing.EndpointMiddleware [1] Ошибка выполнения конечной точки «Web.Controllers.ApiController.Users (Web)»: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware [1] Произошло необработанное исключение при выполнении запроса. System.InvalidOperationException: StatusCode не может быть установлен, потому что ответ уже начался. в Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode (Int32 значение) вMicrosoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode (Int32 значение) в Microsoft.AspNetCore.Http.Internal.DefaultHttpResponse.set_StatusCode (Int32 значение) в Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__7.MoveNext ()

Заранее спасибо за любые идеи о том, как это исправить.

1 Ответ

0 голосов
/ 12 января 2019

Итак, я нашел частичное решение, которое, по крайней мере, разблокирует меня, чтобы я мог продолжить разработку своего API. Попытка изменить контекст. Ответ в JWTBearerEvents OnAuthenticationFailed не работает в моей производственной среде (хотя он отлично работает на моей локальной машине). Я перепробовал множество вариантов, но в итоге единственное, что сработало, это удалить весь этот блок кода из Startup.cs:

options.Events = new JwtBearerEvents()
{
    OnAuthenticationFailed = context =>
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        context.Response.ContentType = "application/json; charset=utf-8";
        var message = _hostingEnvironment.IsDevelopment() ? context.Exception.ToString() : "An error occurred processing your authentication.";
        var result = JsonConvert.SerializeObject(new { message });
        return context.Response.WriteAsync(result);
    }
};

Как только я это сделал, я начал получать 401 код для неудачной проверки токенов при тестировании в Postman, что является хорошей вещью и ожидаемым поведением. Однако в теле ответа также возвращалась страница ошибки по умолчанию HTML.

Чтобы справиться с этим, мне пришлось изменить метод Configure в Startup.cs так, чтобы UseStatusCodePagesWithReExecute игнорировал API:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error/Exception");

        app.UseWhen(context => !context.Request.Path.Value.StartsWith("/api"), builder =>
        {
            builder.UseStatusCodePagesWithReExecute("/Error/{0}");
        });

        app.UseHsts();

        app.UseHttpsRedirection();
    }

    app.UseStaticFiles();

    app.UseCors(Constants.Security.Cors.PolicyName);

    app.UseAuthentication();

    app.UseMvc(ConfigureRoutes);
}

Это работает, но мне это не нравится. Похоже на взлом. Теперь я получаю 401 за неудачную аутентификацию токена и ничего в теле. Как я упоминал ранее, это разблокирует меня, но я все же хотел бы вернуть пользовательское сообщение об ошибке с ответом.

Итак, мой следующий вопрос: если я не смогу использовать JAtBearerEvents OnAuthenticationFailed для добавления сообщения, то где будет правильное место для добавления сообщения об ошибке?

...