从 ASP.NET Core 中的不同 HTTP 标头读取 JWT 令牌

Jos*_*mil 5 c# jwt asp.net-core asp.net-core-authenticationhandler

在 ASP.NET Core API 项目中,我需要验证位于与 Authorization 标头不同的标头中的另一个 JWT Bearer 令牌。例如,假设发送一个 GET 请求来获取产品,/api/products并在名为 的标头中包含承载令牌AccessToken

curl --location --request GET 'https://localhost/api/products' \
--header 'AccessToken: <bearer_token>'
Run Code Online (Sandbox Code Playgroud)

我引用Microsoft.AspNetCore.Authentication.JwtBearer包并在 API 项目中设置身份验证,如下所示:

curl --location --request GET 'https://localhost/api/products' \
--header 'AccessToken: <bearer_token>'
Run Code Online (Sandbox Code Playgroud)

但是,我在JwtBearerOptions Class中找不到有关标头名称的任何内容。

如何配置 JWT 身份验证以从名为“AccessToken”的标头读取 JWT? 是否可以使用 Microsoft.AspNetCore.Authentication.JwtBearer 包?

Jos*_*mil 14

解决方案似乎是使用JwtBearerEvents 类。其中,有一个名为 OnMessageReceived 的委托属性,它“在首次收到协议消息时调用”。该委托将传递MessageReceivedContext类型的对象,其中它有一个名为 Token 的属性,根据文档 “这将使应用程序有机会从备用位置检索令牌”

创建一个继承自 JwtBearerEvents 的类,并在 OnMessageReceived 事件中将上下文对象中的令牌设置为标头“AccessToken”中的值。

/// <summary>
/// Singleton class handler of events related to JWT authentication
/// </summary>
public class AuthEventsHandler : JwtBearerEvents
{
    private const string BearerPrefix = "Bearer ";

    private AuthEventsHandler() => OnMessageReceived = MessageReceivedHandler;

    /// <summary>
    /// Gets single available instance of <see cref="AuthEventsHandler"/>
    /// </summary>
    public static AuthEventsHandler Instance { get; } = new AuthEventsHandler();

    private Task MessageReceivedHandler(MessageReceivedContext context)
    {
        if (context.Request.Headers.TryGetValue("AccessToken", out StringValues headerValue))
        {
            string token = headerValue;
            if (!string.IsNullOrEmpty(token) && token.StartsWith(BearerPrefix))
            {
                token = token.Substring(BearerPrefix.Length);
            }

            context.Token = token;
        }

        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,将事件类添加到 Startup 类的 JWT 身份验证中。

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => 
{
    Configuration.Bind("JwtSettings", options);
    options.Events = AuthEventsHandler.Instance;
});
Run Code Online (Sandbox Code Playgroud)

  • 这是有效的,但是如果找不到令牌,处理程序将回退到检查正常的授权标头。这意味着令牌可以在可能不需要的任一标头中发送。为了防止这种情况发生,如果未找到令牌,您需要调用“context.NoResult()”。如果处理程序看到结果已设置,它将提前返回,而不是继续正常处理。 (2认同)
  • 伙计,你是一个传奇人物 - 根本没有关于如何使用 JwtBearerEvents 的资源 - 这对我帮助很大。我将令牌作为表单内容发布,这允许我使用它而不是身份验证标头。 (2认同)