首页 > 解决方案 > .NET Core 令牌身份验证 - 正文

问题描述

我需要通过 JWT 为 .NET Core Web API 创建自定义身份验证,但要求是客户端希望在 HTTP 请求的正文中发送令牌。

这不是标准方法,.NET Core 默认也不支持。有没有办法从 HTTP 请求正文中获取令牌并将其用于身份验证。

我目前依赖Request.EnableRewind()和使用MemoryStream从正文中读取,然后再次寻找正文的开头,以便稍后控制器可以读取它。这工作得非常好,但如果在短时间内有数千个请求,API 的性能将会下降,这是不好的。

这种方法有什么好的替代方法吗?

services.AddJwtBearer(options =>
{
    options.RequireHttpsMetadata = true;
    options.SaveToken = true;
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(key),
        ValidateIssuer = false,
        ValidateAudience = false, 
        RequireExpirationTime = true,
        ClockSkew = TimeSpan.Zero
    };

    options.Events = new JwtBearerEvents
    {
        OnMessageReceived = ctx =>
        {
            StringValues values;

            if (ctx.Request.Method.Equals("POST"))
            {
                ctx.Request.EnableRewind();
                using (var ms = new MemoryStream())
                {
                    ctx.Request.Body.CopyTo(ms);
                    ms.Seek(0, SeekOrigin.Begin);
                    ctx.Request.Body.Seek(0, SeekOrigin.Begin);
                    using (var reader = new StreamReader(ms))
                    {
                        var jsonBody = reader.ReadToEnd();
                        var body = JsonConvert.DeserializeObject<BaseRequest>(jsonBody);
                        ctx.Token = body.Token;
                        ctx.Request.Headers["Authorization"] = $"Bearer {body.Token}";
                    }
                    return Task.CompletedTask;
                }
            }
            return Task.CompletedTask;
        }
    };
});

标签: authentication.net-corejwtasp.net-core-webapi

解决方案


由于您要求使用另一种方法来使用MemoryStream,因此您Request.EnableBuffering()也许可以使用 。我建议在 devblogs.microsoft.com 上检查“使用 EnableBuffering() 重新读取 ASP.Net Core 请求正文”...

本质上,您OnMessageReceived看起来像这样:

if (ctx.Request.Method.Equals("POST")
{
    ctx.Request.EnableBuffering();
    using (var reader = new StreamReader(ctx.Request.Body, Encoding.UTF8, true, $YOURBUFFERSIZE$, true))
    {
        var jsonBody = reader.ReadToEnd();
        var body = JsonConvert.DeserializeObject<BaseRequest>(jsonBody);
        if (body != null)
        {
            ctx.Token = body.Token;
            ctx.Request.Headers["Authorization"] = $"Bearer {body.Token}";
            ctx.Request.Body.Position = 0;
        }
    }
}

OnMessageReceived坦率地说,这本身并不是最好的方法,但如果你真的想避免修改除MemoryStream.


推荐阅读