zoukankan      html  css  js  c++  java
  • Token refresh的实现

    实现原理:

    在access_token里加入refresh_token标识,给access_token设置短时间的期限(例如一天),给refresh_token设置长时间的期限(例如七天)。当活动用户(拥有access_token)发起request时,在权限验证里,对于requeset的header包含的access_token、refresh_token分别进行验证:

    1、access_token没过期,即通过权限验证;

    2、access_token过期,refresh_token没过期,则返回权限验证失败,并在返回的response的header中加入标识状态的key,在request方法的catch中通过webException来获取标识的key,获取新的token(包含新的access_token和refresh_token),再次发起请求,并返回给客户端请求结果以及新的token,再在客户端更新公共静态token模型;

    3、access_token过期,refresh_token过期即权限验证失败。

    下面展示一下关键代码:

    一、登录生成token的时候加入refresh标识

     public TOKEN GetToken(string username, string password)
            {
                TOKEN token = new TOKEN();
                U_USER model = new BLLU_USER().Token(username, password);
                if (model != null)
                {
                    string pwd = new SDDMD().MD5_jie(model.USERPWD);
                    string md5 = new SDDMD().MD5_jia(model.USERID +"&"+ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") +"&"+ pwd+"&refresh"+ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                    token.access_token = md5;
                    token.token_type = "Authorization";
                    token.expires_in = DateTime.Now.ToString("yyyyMMddHHmmss");
                    //token.refresh_token = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "&refresh";
                }
                return token;
            }

    二、在权限验证环节,对于access_token、refresh_token设置不同时间的期限。再根据判断结果返回状态。

            /// <summary>
            /// 校验token是否有效
            /// </summary>
            /// <param name="encryptTicket">用户提交的Token值</param>
            /// <returns></returns>
            private int ValidateTicket(string encryptTicket)
            {
                try
                {
                    var strTicket = new DBUtility.SDDMD().MD5_jie(encryptTicket);
                    string[] TicketMsg = strTicket.Split('&');
                    if (TicketMsg.Length == 4)
                    {
                        string username = TicketMsg[0];//用户名
                        string passwrod = TicketMsg[2];//密码
                        U_USER model = new BLL.BLLU_USER().Token(username, passwrod);//登陆验证
                        if (model != null)
                        {
                            _userModel = model;
                            //定义Access_Token有效期为1天,精确到秒
                            DateTime dt = Convert.ToDateTime(TicketMsg[1]).AddDays(1);
                            //定义Refresh_Token有效期为1天,精确到秒
                            DateTime dtNew= Convert.ToDateTime(TicketMsg[3].Substring(7)).AddDays(7);//
                            if (dt > DateTime.Now)
                                return 1; //1:access_token没过期
                            else
                            {
                                if (dtNew > DateTime.Now)
                                    return 2; //2:access_token过期,refresh_token没过期
                                else
                                    return 3; //3:access_token过期,refresh_token过期
                            } 
                        }
                        else
                            return 3;
                    }
                    else
                        return 3;
                }
                catch { return 3; }
            }

    三、根据反馈的状态执行不同的方法,“2”(access_token过期,refresh_token没过期)状态下,给返回失败的response的header中加入识别的key值。

            /// <summary>
            /// 定义Access_token验证过期但Reflesh_token有效返回请求刷新token的信息
            /// </summary>
            /// <param name="actionContext"></param>
            protected void RefreshToken(HttpActionContext actionContext)
            {
                var content = "refreshtoken";
                base.HandleUnauthorizedRequest(actionContext);
                var response = actionContext.Response;
                response.StatusCode = HttpStatusCode.Forbidden;
                response.Content = new StringContent(content, Encoding.UTF8, "application/json");
                response.Headers.Add("token", "refresh");//加入识别的key值
            }

    四、request方法中通过Catch捕获webException对象获取Key值,并获取新的token(包含新的access_token和refresh_token),再次发起请求,并返回给客户端请求结果以及新的token。

            /// <summary>
            /// Get head中携带token发送请求
            /// </summary>
            /// <param name="url">WebAPI访问路径</param>
            /// <param name="tokentype">token验证方式 《Authorization》</param>
            /// <param name="tokenvalue">token 《"Bearer " + Token》</param>
            /// <returns></returns>
            public string GetRequest(string url, string tokentype, string tokenvalue)
            {
                try
                {
                    string responseStr = string.Empty;
                    WebRequest request = WebRequest.Create(http + url);
                    request.Timeout = 60000;
                    request.Method = "Get";
                    request.Headers.Add(tokentype, tokenvalue);
                    var response = request.GetResponse();
                    Stream ReceiveStream = response.GetResponseStream();
                    using (StreamReader stream = new StreamReader(ReceiveStream, Encoding.UTF8))
                    {
                        responseStr = stream.ReadToEnd();
                    }
                    return responseStr;
                }
                catch (WebException e)
                {
                    using (WebResponse response = e.Response)
                    {
                        string result=response.Headers.Get("token");//获取识别的KEY
                        if (result == "refresh")//验证是否为状态“2”方法所加的key值
                        {
                            var strTicket = new SDDMD().MD5_jie(tokenvalue.Substring(6));
                            string[] TicketMsg = strTicket.Split('&');
                            string username = TicketMsg[0];//用户名
                            string passwrod = TicketMsg[2];//密码
                            string responseStr = GetRequest("CYUMS/Token/" + username + "/" + passwrod);//获取新的token
                            TOKEN tokenmodel = JsonConvert.DeserializeObject<TOKEN>(responseStr);
                            string secondResponseStr= GetRequest(url, tokenmodel.token_type, "Haval " + tokenmodel.access_token);//再次发起请求
                            return secondResponseStr + "|" + responseStr;//返回请求结果以及新的token
                        }
                        else
                            throw e;
                    }
                }
            }

    五、客户端识别token是否更新,如果更新,就更新公共静态token模型中的access_token的值;

                string user = new HttpHelper().GetRequest(getUserModel, tokenmodel.token_type, "Haval " + tokenmodel.access_token);
                string[] str = user.Split('|');
                if (str.Length == 2)//判断是否有token更新
                {
                    TOKEN tokens = JsonConvert.DeserializeObject<TOKEN>(str[1]);
                    tokenmodel.access_token = tokens.access_token;
                }
                U_USER users = JsonConvert.DeserializeObject<U_USER>(str[0]);
                //business code...
  • 相关阅读:
    python基础之for循环
    python基础之数据类型转换
    python基础之集合set
    python基础之元祖tuple
    python基础之字典dict
    python基础之列表list
    Java基础之数据类型、运算符、标识符
    Java 基础之面向对象
    Java基础之Javadoc的使用
    MYSQL基础之安装、启动、停止、添加、移除、初始化服务
  • 原文地址:https://www.cnblogs.com/wqtmelo/p/8527148.html
Copyright © 2011-2022 走看看