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

Posted

技术标签:

【中文标题】从 ASP.NET Core 中的不同 HTTP 标头读取 JWT 令牌【英文标题】:Read JWT token from different HTTP header in ASP.NET Core 【发布时间】:2021-10-27 17:33:16 【问题描述】:

在 ASP.NET Core API 项目中,我需要验证位于不同于 Authorization 标头的标头中的另一个 JWT Bearer 令牌。例如,假设发送一个 GET 请求以将产品发送到 /api/products,并在名为 AccessToken 的标头中使用 Bearer 令牌。

curl --location --request GET 'https://localhost/api/products' \
--header 'AccessToken: <bearer_token>'

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

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => Configuration.Bind("JwtSettings", options));

但是,我在 JwtBearerOptions Class 中找不到任何有关标题名称的信息。

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

【问题讨论】:

根据来源:github.com/dotnet/aspnetcore/blob/…,此中间件只会查看 auth 标头。如果您想做其他事情,则需要自己编写该中间件。 你必须在你的启动中编写一个自定义中间件。 【参考方案1】:

解决方案似乎是使用JwtBearerEvents class。其中有一个委托property named OnMessageReceived ,它“在第一次收到协议消息时调用”。委托将传递MessageReceivedContext 类型的对象,其中有一个名为Token 的属性according to the documentation “这将使应用程序有机会从其他位置检索令牌”

创建一个继承自 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;
    

最后,在 Startup 类中将 events 类添加到 JWT 身份验证中。

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => 

    Configuration.Bind("JwtSettings", options);
    options.Events = AuthEventsHandler.Instance;
);

【讨论】:

这可行,但是如果找不到令牌,处理程序将回退到检查正常的授权标头。这意味着令牌可以在可能不需要的任一标头中发送。为防止这种情况发生,如果找不到令牌,您需要致电 context.NoResult()。如果处理程序看到结果已设置,它将提前返回,而不是继续正常处理。 伙计,你是一个传奇人物——根本没有关于如何使用 JwtBearerEvents 的资源——这对我帮助很大。我将令牌作为表单内容发布,这允许我使用它而不是 auth 标头。 @pinkfloydx33 你是对的,代码缺少一个部分以避免使用 Authorize 标头的默认设置。我完全错过了,很好!

以上是关于从 ASP.NET Core 中的不同 HTTP 标头读取 JWT 令牌的主要内容,如果未能解决你的问题,请参考以下文章

我想更改 ASP.NET Core 5 MVC 中的路径

ASP.NET Web API 与 ASP.NET Core 中的 URL 匹配差异

带有 SignalR 集线器的 ASP.NET Core 中的范围服务

ASP.Net Core 6,SPA,端点 - 我无法从 http get 请求调用控制器

如何通过 ASP.NET Core 3 中的中间 Web API 传递未更改的 HTTP 响应?

从 DotNetNuke 迁移到 ASP.NET Core