.net core 5.0实现jwt过期一定时间之内自动刷新,一定时间之后返回过期提醒

最近研究了一段时间的.net core整合jwt,感觉比较人性化的解决方案应该是当jwt过期时,应判断过期了多久,如果过期的时间超过某个值,那么则直接返回提醒jwt过期,需要登录,如果没有超过,则直接刷新,提高用户体验的同时,也可以保障一定的安全性。

本项目基于.net core5.0,开发工具vs2019,本文只罗列核心部分,详细源码详见

基于netcore5.0的jwt过期超过一定时间则返回过期提醒,未超过则自动刷新-C#文档类资源-CSDN下载基于netcore5.0的项目整合,涉及jwt配置、jwt刷新、过期判断,拦截器、restful格更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/qq_34309663/85639298下面进行核心功能的详解

首先配置jwt,引用的依赖如下图:

以上两个都有引用,jwtBearer主要用于整合.net core,jwt.net用户对前端传入的token进行检查。

StartUp.cs中配置jwt核心代码如下:

public void ConfigureServices(IServiceCollection services)
        {

           

services.AddControllers(o=> {
                o.Filters.Add<SkipAttribute>();//这个用户标识哪些类需要验证jwt
            })
                //以下语句要求.net core对NewtonsoftJson的支持,这样就可以像以前的web API一样调用了
                .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ContractResolver = new DefaultContractResolver();
            });

            //注册过滤器
            Action<MvcOptions> filters = new Action<MvcOptions>(r => {
                r.Filters.Add(typeof(MyFilters));
                r.Filters.Add(typeof(MyExceptionFilterAttribute));
            });


            services.AddMvc(filters) //注册全局过滤器
                .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

            //添加jwt支持
            services.AddAuthentication
                (a =>
                    {
                        a.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                        a.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                    })
                .AddJwtBearer(j =>
                {
                j.RequireHttpsMetadata = false;
                j.SaveToken = true;
                j.TokenValidationParameters = new TokenValidationParameters
                    {
                        //是否调用对签名securityToken的SecurityKey进行验证
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtTokenString)),//签名秘钥
                        ValidateIssuer = true,//是否验证颁发者
                        ValidIssuer = "Issuer",//颁发者
                        ValidateAudience = true,//是否验证接受者
                        ValidAudience = "Audience",//接收者
                        ValidateLifetime = true,//是否验证失效时间
                        ClockSkew = TimeSpan.Zero,//这句话表示设置过期缓冲时间为0,过期时间一到立即失效
                        RequireExpirationTime = true
                    };
                });

        }

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            //启用静态文件支持,这个必须放在app.UseRouting()上
            app.UseStaticFiles();

            app.UseRouting();

            //添加Cors中间件
            app.UseCors(corsPolicyName);

            //身份认证中间件
            app.UseAuthentication();

            //授权中间件
            app.UseAuthorization();

            //app.UseExceptionHandler();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

下面说下程序运行流程,

用户在前端发送ajax请求,先到达拦截器(过滤器),核心检查都在拦截器中判断,判断是否过期,未过期则放行,过期了,是否未超过1个小时,则刷新token后放行,超过了,则拦截,返回token过期给前端

拦截器核心代码

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using NetCore5.Utils;
using System;
using System.Linq;
using System.Text.RegularExpressions;

namespace NetCore5.Filter
{

    //优先级1:权限过滤器IAuthorizationFilter:它在Filter Pipleline中首先运行,并用于决定当前用户是否有请求权限。如果没有请求权限直接返回。
    public class MyFilters : IAuthorizationFilter
    {
        [Obsolete]
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            //判断是否需要校验
            var isDefined = false;
            var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            if (controllerActionDescriptor != null)
            {
                isDefined = controllerActionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
                   .Any(a => a.GetType().Equals(typeof(SkipAttribute)));
            }
            //是已经标记的不需要检查token的类,则跳过检查
            if (isDefined)
            {
                return;
            }
            var token = context.HttpContext.Request.Headers["Authorization"].ToString();    //ajax请求传过来
            string pattern = "^Bearer (.*?)$";
            if (!Regex.IsMatch(token, pattern))
            {
                context.Result = new ContentResult { StatusCode = 401, Content = "token格式不对!格式为:Bearer {token}" };
                return;
            }
            token = Regex.Match(token, pattern).Groups[1]?.ToString();
            if (token == "null" || string.IsNullOrEmpty(token))
            {
                context.Result = new ContentResult { StatusCode = 401, Content = "token不能为空" };
                return;
            }
            //校验auth的正确性
            var result = TokenHelper.JWTJieM(token);
            //过期了
            if (result == "expired")
            {
               // context.Result = new ContentResult { StatusCode = 401, Content = "登录已过期" };
              //  return;
                //继续判断是否已经过期超过1个小时
                //解析payload,拿到exp
                var exp = TokenHelper.GetExp(token);
                //解析exp具体时间
                DateTime expTime = DateTimeUtil.TimeStampToDateTime(long.Parse(exp));
                //跟当前时间比较,有没有超过1个小时,不超过则刷新,超过则返回token过期,需要重新登录
                bool isExpire = DateTimeUtil.DiffMin(expTime);
                if (isExpire)
                {
                    context.Result = new ContentResult { StatusCode = 401, Content = "登录已过期,请重新登录" };
                    return;
                }
                else
                {
                    //刷新token
                    token = TokenHelper.refreshToken(token);
                }
            }
            else if (result == "invalid")
            {
                context.Result = new ContentResult { StatusCode = 401, Content = "非法操作" };
                return;
            }
            else if (result == "error")
            {
                context.Result = new ContentResult { StatusCode = 401, Content = "出错啦!" };
                return;
            }
        }
    }

        //优先级2:资源过滤器: 它在Authorzation后面运行,同时在后面的其它过滤器完成后还会执行。
        //Resource filters 实现缓存或其它性能原因返回。因为它运行在模型绑定前,所以这里的操作都会影响模型绑定。

       

//注意,异常处理未验证,需要读者自己实践

//优先级4:异常过滤器:被应用全局策略处理未处理的异常发生前异常被写入响应体
        public class MyExceptionFilterAttribute : ExceptionFilterAttribute
        {
            private readonly IModelMetadataProvider _moprovider;
            public MyExceptionFilterAttribute(IModelMetadataProvider moprovider)
            {
                this._moprovider = moprovider;
            }
            public override void OnException(ExceptionContext context)
            {
                base.OnException(context);
                if (!context.ExceptionHandled)//如果异常没有被处理过
                {
                    string controllerName = (string)context.RouteData.Values["controller"];
                    string actionName = (string)context.RouteData.Values["action"];
                    //string msgTemplate =string.Format( "在执行controller[{0}的{1}]方法时产生异常",controllerName,actionName);//写入日志

                    if (this.IsAjaxRequest(context.HttpContext.Request))
                    {

                        context.Result = new JsonResult(new
                        {
                            Result = false,
                            PromptMsg = "系统出现异常,请联系管理员",
                            DebugMessage = context.Exception.Message
                        });
                    }
                    else
                    {
                        var result = new ViewResult { ViewName = "~Views/Shared/Error.cshtml" };
                        result.ViewData = new ViewDataDictionary(_moprovider, context.ModelState);
                        result.ViewData.Add("Execption", context.Exception);
                        context.Result = result;
                    }
                }
            }
            //判断是否为ajax请求
            private bool IsAjaxRequest(HttpRequest request)
            {
                string header = request.Headers["X-Requested-With"];
                return "XMLHttpRequest".Equals(header);
            }
        }


        public class SkipAttribute : Attribute, IFilterMetadata
        {
            ///允许未通过身份验证也可以访问的特性
        }

}

到此,核心代码介绍完毕,详细源码请见开头的下载链接
 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
.NET Core中,可以通过使用中间件来捕捉JWT过期事件。以下是捕捉JWT过期事件的步骤: 1. 首先,在项目中添加Microsoft.AspNetCore.Authentication.JwtBearer包。这是一个用于JWT身份验证的官方包。 2. 在Startup.cs文件的ConfigureServices方法中,添加JWT身份验证服务: ``` services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "your_issuer", ValidAudience = "your_audience", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_security_key")), // 捕捉JWT过期事件 Events = new JwtBearerEvents { OnAuthenticationFailed = context => { if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { // JWT过期 // 在这里处理过期事件 } return Task.CompletedTask; } } }; }); ``` 注意,在上述代码中你需要自己设置issuer、audience和security key的值。另外,在"// 在这里处理过期事件"的注释处,你可以编写自己的代码来处理JWT过期事件。 3. 在Startup.cs文件的Configure方法中,添加身份验证中间件: ``` app.UseAuthentication(); ``` 通过以上步骤,当JWT过期时,OnAuthenticationFailed事件会被触发,并在事件处理程序中执行相应的操作。你可以通过编写自定义的代码来处理JWT过期事件,例如重新生成一个新的JWT等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值