.Net Core下简单的JWT黑名单中间件

Posted 娃都会打酱油了

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.Net Core下简单的JWT黑名单中间件相关的知识,希望对你有一定的参考价值。

自从JWT认证方式在互联网上蔓延后,Session认证方式就被挤掉了一大半的生存空间,这里我们不讲JWT与Session两种方式的优缺点,我们只讲如何通过JWT的黑名单来阻止某些Token的登录。

设置黑名单,也就是说要将Token写入某个存储介质,然后考虑数据并不需要一直存在,其在有效期之后应自动释放,那这种情况下存储介质首选肯定是缓存,鉴于目前流行容器化技术,微服务概念又漫天飞的情况,缓存还得考虑支持分布式,那妥妥的必选方案就是IDistributedCache,这样究竟是单体应用MemoryCache,还是分布式Redis,亦或是其它方式都可以任君选择。

选好了存储介质,那就要确定程序通过什么标志来判断确定当前是要将Token写入黑名单,一般来说Authorization是写在HttpHeader里,那我们也可以考虑在HttpHeader里增加一个Key来标志当前请求是要注册黑名单,这里我们选用Loginout,毕竟一般来说也就是退出登录时,才需要设置黑名单。

下面开始来具体的代码,这里是按照微软定义的Restful规范通过StatusCode来返回执行结果

    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Caching.Distributed;
    public class JWTBlacklistMiddleware
    {
        private const string AuthenticationHeader = "Authorization";
        private const string AuthenticationScheme = "Bearer";
        private const string LoginoutHeader = "Loginout";//退出登录的Header
        private const int CacheExpiration = 36000;//缓存过期时间 秒,不解析jwt数据,直接将缓存时间设置为Token的最大有效时间,以空间换性能

        private readonly RequestDelegate _next;
        private readonly IDistributedCache _cache;

        public JWTBlacklistMiddleware(RequestDelegate next, IDistributedCache cache)
        {
            this._next = next;
            this._cache = cache;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            var auth = context.Request.Headers[AuthenticationHeader].FirstOrDefault();
            if (!string.IsNullOrWhiteSpace(auth) && auth.StartsWith(AuthenticationScheme))
            {
                var token = auth.Substring(AuthenticationScheme.Length).Trim();
                var tokenMd5 = MD5Helper.HashOf(token);//通过摘要方式降低存储空间,如果担心碰撞问题导致不应该过期的Token也过期了,可以将整个Token作为Key的一部分,Redis的Key支持512M
                var cacheKey = $"TokenBLK:{tokenMd5}";
                if (context.Request.Headers[LoginoutHeader].FirstOrDefault() != null)//只要带了LoginoutHeader并且value不为null,就认为是要记录黑名单
                {
                    //将Token的摘要写入黑名单
                    await this._cache.SetStringAsync(cacheKey, "1", new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(CacheExpiration)
                    });
                    context.Response.StatusCode = 200;
                    return;
                }
                else if ((await this._cache.GetStringAsync(cacheKey)) != null)
                {//如果是黑名单,直接返回401
                    context.Response.StatusCode = 401;
                    return;
                }
            }
            await this._next(context);
        }
    }

上面代码中的MD5Helper具体源码可见此处
使用时也只需要在StartupUseMiddleware,然后需注意下Use的位置,一般来说应该在UseStaticFiles之后,在UseAuthentication之前

        public void Configure(IApplicationBuilder app, IHostEnvironment env)
        {
            app.UseMiddleware<JWTBlacklistMiddleware>();
        }

以上是关于.Net Core下简单的JWT黑名单中间件的主要内容,如果未能解决你的问题,请参考以下文章

.Net Core JWT 身份验证与自定义 API 密钥中间件

Asp.Net Core安全防护-客户端IP白名单限制

如何手动验证 JWT Asp.Net Core?

如何使用.Net Core cookie中间件ticketdataformat将Jwt令牌从Api保存到c#中的cookie

黑名单/验证/生成 JWT 刷新令牌

使用 .NET Core 的 Firebase 身份验证 (JWT)