如何从JwtSecurityTokenHandler获取日志输出?

时间:2018-10-02 04:22:37

标签: asp.net asp.net-core jwt

我有一个ASP.NET Core 2.1 Web应用程序项目,该项目使用JWT令牌对项目中内置的Web API进行身份验证。当我在计算机上本地运行它时,它可以很好地工作,但是当我将其部署到Azure(具有相同的环境和应用程序设置)时,它只返回空的HTTP 401响应,以响应来自经过身份验证的客户端的请求,我需要找出原因,可以解决它。

我启用了ASP.NET Core中每个细节的日志记录,但是我从未收到任何有用的输出。

首先,我通过NuGet将Serilog.AspNetCore和控制台接收器添加到项目中,然后在Verbose中的Program.cs级别配置日志记录:

public class Program
{
    public static void Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Verbose()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Verbose)
            .MinimumLevel.Override("System", LogEventLevel.Verbose)
            .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Verbose)
            .Enrich.FromLogContext()
            .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate)
            .CreateLogger();

        CreateWebHostBuilder( args ).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(String[] args)
    {
        return WebHost.CreateDefaultBuilder( args )
            .ConfigureLogging( (ctx, cfg ) =>
            {
                cfg.ClearProviders();
            } )
            .UseStartup<Startup>()
            .UseSerilog();
    }
}

但是当我在Azure上运行Web应用程序(使用控制台stdout记录到文件)时,我得到了以下输出:

[04:13:10 Verbose] Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker
Authorization Filter: Before executing OnAuthorizationAsync on filter 
Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter.

[04:13:10 Verbose] 
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler
HandleAuthenticateAsync called

[04:13:10 Debug] 
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler
AuthenticationScheme: Bearer was not authenticated.

[04:13:10 Information] 
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService
Authorization failed.

[04:13:10 Verbose] Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker
Authorization Filter: After executing OnAuthorizationAsync on filter 
Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter.

[04:13:10 Information] 
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.

[04:13:10 Verbose] Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker
Before executing action result Microsoft.AspNetCore.Mvc.ChallengeResult.

[04:13:10 Information] Microsoft.AspNetCore.Mvc.ChallengeResult
Executing ChallengeResult with authentication schemes (["Bearer"]).

[04:13:10 Verbose] 
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler
Forwarding challenge to scheme: BearerIdentityServerAuthenticationJwt

请注意,尽管进行了冗长的日志记录,但错误消息(以下重复)却没有给我任何解释:

AuthenticationScheme: Bearer was not authenticated.
Authorization failed.

我仔细研究了ASP.NET Core Security源代码,发现JwtBearerHandler.HandleAuthenticateAsync本身并没有做太多日志记录,但是它确实调用了非开源System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler通常会进行很多日志记录,包括详细的原因(例如(在字符串中带有IDX10209型错误代码),但我不知道为什么它没有输出我可以捕获的任何内容。

如何记录来自JwtSecurityTokenHandler的消息?

1 个答案:

答案 0 :(得分:1)

我发现了问题:

  • 我的HttpClient(正在发送HTTP Authorization标头不记名令牌)被无意发送到http:// URI,该URI立即收到301重定向到https:// URI。重定向是由IIS执行的,没有涉及ASP.NET Core管道。
  • 在重定向之后,HttpClient类不会重新发送Authorization标头(这是by-design)。
    • 我从没注意到这一点,因为我的HttpClient收到的HttpResponseMessage引用了带有Authorization标头的原始请求,而不是后标。缺少标题的重定向请求。我必须将Fiddler与HTTPS代理一起使用,以查看第二个请求缺少Authorization标头。
  • IdentityServerAuthenticationHandler或ASP.NET Core自己的JwtBearerHandler收到不带Authorization头的请求时,它根本不会调用JwtSecurityTokenHandler。为此,请在ASP.NET Core Security Git存储库中打开JwtBearerHandler.cs文件,然后查看HandleAuthenticateAsync:它具有以下逻辑:

    if (string.IsNullOrEmpty(token))
    {
        string authorization = Request.Headers["Authorization"];
    
        // If no authorization header found, nothing to process further
        if (string.IsNullOrEmpty(authorization))
        {
            return AuthenticateResult.NoResult();
        }
    
  • 因此,在我的情况下,它实际上从未调用过JwtSecurityTokenHandler,因此缺少有关JWT验证的输出消息。

  • 但是我收到的输出消息没有帮助。它们都具有误导性:

    • “ AuthenticationScheme:承载未通过身份验证。”应该类似于“ AuthenticationScheme:请求中不存在Bearer令牌”。代替。
    • “授权失败。”应该是“由于请求中没有令牌,所以跳过了授权。”
  • 因此,最后,解决方法是将原始请求URI的方案从http://更改为https://