欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-08 23:03:47
.net core webapi jwt 更为清爽的认证 后续:续期以及设置Token过期 续期: 续期的操作是在中间件中进行的,续期本身包括了前一个Token的过期加发放新的Token,所以在说续期前先说Token过期 在开始之前先增加相应的配置:续期间隔 和 续期携带给前端的新Token的Hea ......

.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; }
    }

 

1.设置token过期

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

public static list<string> invalidatetokens = new list<string>();

然后添加 jwt中添加方法:

bool invalidatetoken(string token);
public bool invalidatetoken(string token)
        {
            if (!invalidatetokens.contains(token))
            {
                invalidatetokens.add(token);
            }
            return true;
        }

修改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);
        }

修改: 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;
            }
        }

 

紧接着在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过来就可以