• .net core webapi jwt 更为清爽的认证 ,续期很简单(2)


    .net core webapi jwt 更为清爽的认证  后续:续期以及设置Token过期

    续期: 续期的操作是在中间件中进行的,续期本身包括了前一个Token的过期加发放新的Token,所以在说续期前先说Token过期

    在开始之前先增加相应的配置:续期间隔 和 续期携带给前端的新Token的Head.jwtConfig同步修改

     "Jwt": {
        "Issuer": "issuer",
        "Audience": "Audience",
        "SecretKey": "abc",
        "Lifetime": 20, //单位分钟
        "RenewalTime": 10, //单位分钟,Token续期的时间间隔,10表示超过10分钟再次请求就续期
        "ValidateLifetime": true,
        "HeadField": "Auth", //头字段
        "ReTokenHeadField": "ReToken",
        "Prefix": "", //前缀
        "IgnoreUrls": [ "/swagger/index.html", "/swagger/v1/swagger.json", "/Auth/GetToken", "/Auth/InvalidateToken" ]
      }
     internal class JwtConfig
        {
            public string Issuer { get; set; }
            public string Audience { get; set; }
    
            /// <summary>
            /// 加密key
            /// </summary>
            public string SecretKey { get; set; }
            /// <summary>
            /// 生命周期
            /// </summary>
            public int Lifetime { get; set; }
            /// <summary>
            /// 续期时间
            /// </summary>
            public int RenewalTime { get; set; }
            /// <summary>
            /// 是否验证生命周期
            /// </summary>
            public bool ValidateLifetime { get; set; }
            /// <summary>
            /// 验证头字段
            /// </summary>
            public string HeadField { get; set; }
            /// <summary>
            /// 新Token的Head字段
            /// </summary>
            public string ReTokenHeadField { get; set; }
            /// <summary>
            /// jwt验证前缀
            /// </summary>
            public string Prefix { get; set; }
            /// <summary>
            /// 忽略验证的url
            /// </summary>
            public List<string> IgnoreUrls { get; set; }
        }
    View Code

    1.设置Token过期

    首先在Jwt.cs中增加静态属性 

    public static List<string> InvalidateTokens = new List<string>();

    然后添加 Jwt中添加方法:

    bool InvalidateToken(string Token);
    View Code
    public bool InvalidateToken(string Token)
            {
                if (!InvalidateTokens.Contains(Token))
                {
                    InvalidateTokens.Add(Token);
                }
                return true;
            }
    View Code

    修改Jwt中GetToken的方法:

    string GetToken(IDictionary<string, string> Clims,string OldToken=null);
      public string GetToken(IDictionary<string, string> Claims,string OldToken=null)
            {
                List<Claim> claimsAll = new List<Claim>();
                foreach (var item in Claims)
                {
                    claimsAll.Add(new Claim(item.Key, item.Value??""));
                }
                var symmetricKey = Convert.FromBase64String(this._base64Secret);
                var tokenHandler = new JwtSecurityTokenHandler();
                var tokenDescriptor = new SecurityTokenDescriptor
                {
                    Issuer = _jwtConfig.Issuer,
                    Audience = _jwtConfig.Audience,
                    Subject = new ClaimsIdentity(claimsAll),
                    NotBefore = DateTime.Now,
                    Expires = DateTime.Now.AddMinutes(this._jwtConfig.Lifetime),
                    SigningCredentials =new SigningCredentials(new SymmetricSecurityKey(symmetricKey),
                                               SecurityAlgorithms.HmacSha256Signature)
                };
                var securityToken = tokenHandler.CreateToken(tokenDescriptor);
                if (!string.IsNullOrEmpty(OldToken))//执行旧Token过期
                {
                    if (!InvalidateTokens.Contains(OldToken))
                    {
                        InvalidateTokens.Add(OldToken);
                    }
                }
                return tokenHandler.WriteToken(securityToken);
            }
    View Code

    修改: ValidateToken

      public bool ValidateToken(string Token, out Dictionary<string, string> Clims)
            {
                Clims = new Dictionary<string, string>();
                if (InvalidateTokens.Contains(Token))
                {
                    return false;
                }
                ClaimsPrincipal principal = null;
                if (string.IsNullOrWhiteSpace(Token))
                {
                    return false;
                }
                var handler = new JwtSecurityTokenHandler();
                try
                {
                    var jwt = handler.ReadJwtToken(Token);
                    if (jwt == null)
                    {
                        return false;
                    }
                    var secretBytes = Convert.FromBase64String(this._base64Secret);
                    var validationParameters = new TokenValidationParameters
                    {
                        RequireExpirationTime = true,
                        IssuerSigningKey = new SymmetricSecurityKey(secretBytes),
                        ClockSkew = TimeSpan.Zero,
                        ValidateIssuer = true,//是否验证Issuer
                        ValidateAudience = true,//是否验证Audience
                        ValidateLifetime = this._jwtConfig.ValidateLifetime,//是否验证失效时间
                        ValidateIssuerSigningKey = true,//是否验证SecurityKey
                        ValidAudience = this._jwtConfig.Audience,
                        ValidIssuer = this._jwtConfig.Issuer
                    };
                    SecurityToken securityToken;
                    principal = handler.ValidateToken(Token, validationParameters, out securityToken);
                    foreach (var item in principal.Claims)
                    {
                        Clims.Add(item.Type, item.Value);
                    }
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                    return false;
                }
            }
    View Code

    紧接着在Auth中增加接口

    /// <summary>
            /// 强制Token失效
            /// </summary>
            /// <param name="Token"></param>
            /// <returns></returns>
            [HttpPost]
            public IActionResult InvalidateToken(string Token)
            {
                return new JsonResult(this._jwt.InvalidateToken(Token));
            }

    //需要让当前Token强制过期的时候,客户端调用 InvalidateToken 传入当前Token就可以

    2.续期:修改中间件:UseJwtMiddleware

    public class UseJwtMiddleware
        {
            private readonly RequestDelegate _next;
            private JwtConfig _jwtConfig =new JwtConfig();
            private IJwt _jwt;
            public UseJwtMiddleware(RequestDelegate next, IConfiguration configration,IJwt jwt)
            {
                _next = next;
                this._jwt = jwt;
                configration.GetSection("Jwt").Bind(_jwtConfig);
            }
            public Task InvokeAsync(HttpContext context)
            {
                if (_jwtConfig.IgnoreUrls.Contains(context.Request.Path))
                {
                    return this._next(context);
                }
                else
                {
                    if (context.Request.Headers.TryGetValue(this._jwtConfig.HeadField, out Microsoft.Extensions.Primitives.StringValues authValue))
                    {
                        var authstr = authValue.ToString();
                        if (this._jwtConfig.Prefix.Length > 0)
                        {
                            authstr = authValue.ToString().Substring(this._jwtConfig.Prefix.Length+1, authValue.ToString().Length -(this._jwtConfig.Prefix.Length+1));
                        }
                        if (this._jwt.ValidateToken(authstr, out Dictionary<string, string> Clims)&&!Jwt.InvalidateTokens.Contains(authstr))
                        {
                            List<string> climsKeys = new List<string>() { "nbf", "exp", "iat", "iss","aud" };
                            IDictionary<string, string> RenewalDic = new Dictionary<string, string>();
                            foreach (var item in Clims)
                            {
                                if (climsKeys.FirstOrDefault(o=>o==item.Key) == null)
                                {
                                    context.Items.Add(item.Key, item.Value);
                                    RenewalDic.Add(item.Key, item.Value);
                                }
                            }
                            //验证通过的情况下判断续期时间
                            if (Clims.Keys.FirstOrDefault(o => o == "exp") != null)
                            {
                                var start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                                var timespan = long.Parse(Clims["exp"]);
                                var expDate = start.AddSeconds(timespan).ToLocalTime();
                                var o = expDate - DateTime.Now;
                                if (o.TotalMinutes < _jwtConfig.RenewalTime)
                                {
                                    //执行续期当前Token立马失效
                                    //var newToken = this._jwt.GetToken(RenewalDic, authstr);
                       //var newToken=this._jwt.GetToken(RenewalDic);//生成新Token当前Token仍可用,过期时间以Lifetime设置为准 context.Response.Headers.Add(_jwtConfig.ReTokenHeadField, newToken); } }
    return this._next(context); } else { context.Response.StatusCode = 401; context.Response.ContentType = "application/json"; return context.Response.WriteAsync("{"status":401,"statusMsg":"auth vaild fail"}"); } } else { context.Response.StatusCode = 401; context.Response.ContentType = "application/json"; return context.Response.WriteAsync("{"status":401,"statusMsg":"auth vaild fail"}"); } } } }

    本例中,当客户端获取Token超过10分钟未超过20分钟的这个时间段如果再执行请求,那么服务端就会给Head头上带上 ReToken:newToken

    下次请求带着新Token过来就可以

  • 相关阅读:
    突发奇想:消息机制,以及Windows自带控件,都可以到ReactOS里去寻找答案
    调用QQ截图
    半同步半异步模式的实现
    TFS二次开发系列:四、TFS二次开发WorkItem添加和修改、保存
    NodeJS系列-部署
    GiftWrapping算法解决二维凸包问题
    案例研究:Web应用出现间歇性的SqlException
    sql数据库的备份还原问题
    shuttle.esb
    上传图片时生成缩略图,可以自定义图片尺寸
  • 原文地址:https://www.cnblogs.com/zzfstudy/p/10931348.html
Copyright © 2020-2023  润新知