实现原理:

在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标识

  1. public TOKEN GetToken(string username, string password)
  2. {
  3. TOKEN token = new TOKEN();
  4. U_USER model = new BLLU_USER().Token(username, password);
  5. if (model != null)
  6. {
  7. string pwd = new SDDMD().MD5_jie(model.USERPWD);
  8. 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"));
  9. token.access_token = md5;
  10. token.token_type = "Authorization";
  11. token.expires_in = DateTime.Now.ToString("yyyyMMddHHmmss");
  12. //token.refresh_token = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "&refresh";
  13. }
  14. return token;
  15. }

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

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

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

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

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

  1. /// <summary>
  2. /// Get head中携带token发送请求
  3. /// </summary>
  4. /// <param name="url">WebAPI访问路径</param>
  5. /// <param name="tokentype">token验证方式 《Authorization》</param>
  6. /// <param name="tokenvalue">token 《"Bearer " + Token》</param>
  7. /// <returns></returns>
  8. public string GetRequest(string url, string tokentype, string tokenvalue)
  9. {
  10. try
  11. {
  12. string responseStr = string.Empty;
  13. WebRequest request = WebRequest.Create(http + url);
  14. request.Timeout = 60000;
  15. request.Method = "Get";
  16. request.Headers.Add(tokentype, tokenvalue);
  17. var response = request.GetResponse();
  18. Stream ReceiveStream = response.GetResponseStream();
  19. using (StreamReader stream = new StreamReader(ReceiveStream, Encoding.UTF8))
  20. {
  21. responseStr = stream.ReadToEnd();
  22. }
  23. return responseStr;
  24. }
  25. catch (WebException e)
  26. {
  27. using (WebResponse response = e.Response)
  28. {
  29. string result=response.Headers.Get("token");//获取识别的KEY
  30. if (result == "refresh")//验证是否为状态“2”方法所加的key值
  31. {
  32. var strTicket = new SDDMD().MD5_jie(tokenvalue.Substring(6));
  33. string[] TicketMsg = strTicket.Split('&');
  34. string username = TicketMsg[0];//用户名
  35. string passwrod = TicketMsg[2];//密码
  36. string responseStr = GetRequest("CYUMS/Token/" + username + "/" + passwrod);//获取新的token
  37. TOKEN tokenmodel = JsonConvert.DeserializeObject<TOKEN>(responseStr);
  38. string secondResponseStr= GetRequest(url, tokenmodel.token_type, "Haval " + tokenmodel.access_token);//再次发起请求
  39. return secondResponseStr + "|" + responseStr;//返回请求结果以及新的token
  40. }
  41. else
  42. throw e;
  43. }
  44. }
  45. }

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

  1. string user = new HttpHelper().GetRequest(getUserModel, tokenmodel.token_type, "Haval " + tokenmodel.access_token);
  2. string[] str = user.Split('|');
  3. if (str.Length == 2)//判断是否有token更新
  4. {
  5. TOKEN tokens = JsonConvert.DeserializeObject<TOKEN>(str[1]);
  6. tokenmodel.access_token = tokens.access_token;
  7. }
  8. U_USER users = JsonConvert.DeserializeObject<U_USER>(str[0]);
  9. //business code...

 

版权声明:本文为wqtmelo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/wqtmelo/p/8527148.html