【问题标题】:JWT BearerHandler Token Falied but request is still processedJWTBearerHandler 令牌失败,但请求仍在处理中
【发布时间】:2019-11-12 23:33:00
【问题描述】:

我遇到了一个非常奇怪的问题,我猜我的设置中遗漏了一些东西。

我有一个由 IdentityServer4 保护的 WebAPI。它仅使用 Client_credentials。如果我写了错误的 ClientId och ClientSecret 该用户未通过身份验证,并且我无法连接到我的 WebAPI。但是如果我写了错误的范围名称,请求仍然被处理并且我得到了我的响应,奇怪的是抛出了一个异常,但由于某种原因它被 .NET Core Framework 忽略了。

这是我的输出窗口中的一些调试信息。

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: 请求开始 HTTP/1.1 GET https://localhost:44360/v1/bookings

    Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10214: Audience validation failed. Audiences: '[PII is hidden]'. Did not match: validationParameters.ValidAudience: '[PII is hidden]' or validationParameters.ValidAudiences: '[PII is hidden]'.
           at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
           at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateAudience(IEnumerable`1 audiences, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
           at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
           at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
           at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
        Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: Bearer was not authenticated. Failure message: IDX10214: Audience validation failed. Audiences: '[PII is hidden]'. Did not match: validationParameters.ValidAudience: '[PII is hidden]' or validationParameters.ValidAudiences: '[PII is hidden]'.
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executing endpoint 'TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api)'
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Get", controller = "Bookings"}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult`1[System.Collections.Generic.IEnumerable`1[System.String]]] Get() on controller TRS.BookingService.Api.Controllers.BookingsController (TRS.BookingService.Api).
        Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api) - Validation state: Valid
        TRS.BookingService.Api.Controllers.BookingsController:Information: Getting all bookings
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 96.2159ms.
Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor:Information: Executing ObjectResult, writing value of type 'System.String[]'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api) in 280.2344ms
Microsoft.AspNetCore.Routing.EndpointMiddleware:Information: Executed endpoint 'TRS.BookingService.Api.Controllers.BookingsController.Get (TRS.BookingService.Api)'
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 1345.3829ms 200 application/json; charset=utf-8

因此,即使抛出了表示令牌未验证的异常,仍然允许请求继续并执行并将响应发送回客户端。

这是 ConfigureServices 的样子:

    services
        .AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(options =>
        {
            options.Authority = "https://localhost:44392/";
            options.Audience = "FAKE_SCOPE";
        });

还有 Configure() 方法

    app.UseAuthentication();
    app.UseMvc();

这是 JWT 令牌的样子:

{
  "nbf": 1562062882,
  "exp": 1562066482,
  "iss": "https://localhost:44392",
  "aud": [
    "https://localhost:44392/resources",
    "bookingApi"
  ],
  "client_id": "clientId",
  "scope": [
    "bookingApi"
  ]
}

这是调用 API 的客户端代码。

        var idpUrl = "https://localhost:44392/";    
        var clientId = "clientId";
        var clientSecret = "secret";
        var scope = "bookingApi";

        var accessToken = await GetAccessTokenAsync(new Uri(idpUrl), clientId, clientSecret, scope);
        string content = await GetContent(new Uri("https://localhost:44360/v1/bookings"), accessToken);

我想我在授权方面错过了一些东西,我尝试了不同的

services.Authorization()

在 ConfigureServices() 方法中但是没有用,估计是我写错了。

最好的问候 马格努斯

【问题讨论】:

  • 您是否在BookingsController.Get() 上方添加了Authorize 属性?
  • 是的,否则没有进行任何授权。
  • 我看到了你的答案。这一定不是预期的行为。过滤器(即)属性必须中断流程。而且我很确定它按预期对我有用。将重新检查。你用的是什么版本的asp.net core?它们的行为都略有不同
  • 是的,我知道,这不应该是预期的行为。我用的是2.2版本。
  • 从默认模板创建 API 解决方案。 “按原样”开始:从localhost:57358/api/values 得到200。补充:services.AddAuthentication(options => {options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;}).AddJwtBearer(options =>{options.Authority = "https://login.dev.xxx.com/"; //options.Audience = "FAKE_SCOPE";}); + AuthorizeValues 控制器上——得到401 + WWW-Authenticate: Bearer error="invalid_token", error_description="The audience is invalid"

标签: jwt identityserver4 asp.net-authorization


【解决方案1】:

在遇到同样的问题后,我看到了这篇文章。在敲了很多敲门之后,我发现我的情况是使用 services.AddMvcCore()(在我的情况下使用 .AddJsonFormatters().AddDataAnnotations())而不是 services.AddMvc() 引起的。只有使用 .AddMvcCore() 才能获得 401 令牌验证失败。

似乎您需要在使用 .AddMvcCore 时将 .AddAuthorization() 添加到组合中,因为默认情况下不添加它。没有它,令牌验证会失败,但请求管道会非常愉快地继续。

【讨论】:

    【解决方案2】:

    花了一天时间试图弄清楚为什么它不起作用后,我决定逐步检查 Microsoft 代码并在 AuthenticationMiddleware 中找到它。

    公共类 AuthenticationMiddleware { 私有只读 RequestDelegate _next;

    public AuthenticationMiddleware(RequestDelegate next, IAuthenticationSchemeProvider schemes)
    {
        if (next == null)
        {
            throw new ArgumentNullException(nameof(next));
        }
        if (schemes == null)
        {
            throw new ArgumentNullException(nameof(schemes));
        }
    
        _next = next;
        Schemes = schemes;
    }
    
    public IAuthenticationSchemeProvider Schemes { get; set; }
    
    public async Task Invoke(HttpContext context)
    {
        context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
        {
            OriginalPath = context.Request.Path,
            OriginalPathBase = context.Request.PathBase
        });
    
        // Give any IAuthenticationRequestHandler schemes a chance to handle the request
        var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
        foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
        {
            var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;
            if (handler != null && await handler.HandleRequestAsync())
            {
                return;
            }
        }
    
        var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
        if (defaultAuthenticate != null)
        {
            var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
            if (result?.Principal != null)
            {
                context.User = result.Principal;
            }
        }
    
        await _next(context);
    }
    

    }

    基本上发生的事情是结果上有一个失败属性,其中包含我的身份验证异常,但由于代码中没有检查它,它将继续请求管道中的下一个中间件。所以我基本上写了我自己的 AuthenticationMiddleware 添加一个检查失败是否有值然后返回 403。

            var defaultAuthenticate = await _schemas.GetDefaultAuthenticateSchemeAsync();
            if (defaultAuthenticate != null)
            {
                var result = await context.AuthenticateAsync(defaultAuthenticate.Name);
                if (result?.Principal != null)
                    context.User = result.Principal;
    
                if (result?.Failure != null)
                    throw new AuthorizationException(result.Failure.Message);
            }
    
            await _next(context);
        }
        catch (AuthorizationException ex) when (!context.Response.HasStarted)
        {
            _logger.LogWarning(ex, "Unauthorized access encountered.");
    
            context.Response.Clear();
            context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
        }
    

    然而,除了我之外,这不是我要做的事情,所以如果有人知道我为什么需要这样做,我会很高兴提供信息。

    【讨论】:

      猜你喜欢
      • 2017-06-23
      • 1970-01-01
      • 2013-05-02
      • 2013-10-22
      • 1970-01-01
      • 2014-08-28
      • 2011-08-01
      • 2013-12-01
      • 1970-01-01
      相关资源
      最近更新 更多