.NET Core令牌身份验证-正文

时间:2019-10-08 13:46:48

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

我需要通过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;
        }
    };
});

1 个答案:

答案 0 :(得分:1)

由于您要求使用MemoryStream的替代方法,因此也许可以使用Request.EnableBuffering()。我建议在devblogs.microsoft.com上检查“ Re-reading ASP.Net Core request bodies with EnableBuffering()”。

基本上,您的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