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

5
在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类中,我找不到任何关于头部名称的信息。

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


1
根据源代码:https://github.com/dotnet/aspnetcore/blob/8b30d862de6c9146f466061d51aa3f1414ee2337/src/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs#L53,这个中间件仅会查看身份验证头。如果您想要做其他事情,您需要自己编写该中间件。 - David L
1
你需要在启动器内编写自定义中间件。 - Fabien Sartori
1个回答

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;
    }
}

最后,在启动类中将“events”类添加到JWT身份验证中。
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => 
{
    Configuration.Bind("JwtSettings", options);
    options.Events = AuthEventsHandler.Instance;
});

2
这个方法是有效的,但是如果找不到令牌,处理程序将会回退到检查普通的授权头。这意味着令牌可以在任一头中发送,这可能不是想要的。为了防止这种情况发生,如果找不到令牌,你需要调用 context.NoResult()。如果处理程序看到结果已经被设置,它将提前返回,而不是继续正常处理。 - pinkfloydx33
2
伙计,你真是个传奇——关于如何使用JwtBearerEvents的资源根本没有,这对我帮助很大。我将令牌作为表单内容发布,这使我可以使用它而不是身份验证标头。 - sommmen
@pinkfloydx33,你说得对,代码缺少一个部分来避免回退到使用授权标头的默认设置。我完全忽略了它,很好地捕捉到了! - Jossean Yamil
1
希望我能为你的这个发现和解释送上大量的赞扬。太棒了! - kiddailey
1
非常有价值的答案。我想说的一件事是,在检查它是否以“Bearer”开头时使用不区分大小写:token.StartsWith(BearerPrefix, StringComparison.InvariantCultureIgnoreCase) 我的令牌有时以“Bearer …”开头,其他时候以“bearer …”开头。 - Andrej Mohar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接