vue的token刷新处理的方法


Posted in Javascript onJuly 17, 2018

第一次接触token处理,初来乍到,说错的地方还请各位多多指教。

token身份验证机制

客户端登录请求成功后,服务器将用户信息(如用户id)使用特殊算法加密后作为验证的标志发送给用户(即token),当用户下次发起请求时,会将这个token捎带过来,服务器再将这个token通过解密后进行验证,通过的话,则向客户端返回请求的数据;反之,则请求失败。

token优点

它是无状态的,且服务器不用像传统的身份认证(session)那样需要保存会话信息,减轻了服务器的压力。

vue的token刷新处理

在对token身份验证机制进行一次简单介绍后,进入正文...

一般为了安全性,token都会设置一个过期时间,在过期之后就无法请求相关接口了,这时应该怎么办呢,是直接退出登录吗?

在目前公司的项目里,为了更好的用户体验,我们选择手动刷新token。登录请求成功后,会返回一个token和token过期时间,在每次请求api时,前端可以先判断一下token是否即将过期或已过期,如果是,则请求刷新token的接口,成功替换原来的token之后才可以重新发起请求。

下面,我们直接看代码,这是在vue的请求拦截器里进行的相关操作:

/*是否有请求正在刷新token*/
window.isRefreshing = false
/*被挂起的请求数组*/
let refreshSubscribers = []

/*获取刷新token请求的token*/
function getRefreshToken () {
 return JSON.parse(localStorage.auth).refresh_token
}

/*push所有请求到数组中*/
function subscribeTokenRefresh (cb) {
 refreshSubscribers.push(cb)
}

/*刷新请求(refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据)*/
function onRrefreshed (token) {
 refreshSubscribers.map(cb => cb(token))
}

/*请求拦截器*/
ajax.interceptors.request.use(
 config => {
  const authTmp = localStorage.auth
  /*判断是否已登录*/
  if (authTmp) {
   /*解析登录信息*/
   let auth = JSON.parse(authTmp)
   /*判断auth是否存在*/
   if (auth) {
    /*在请求头中添加token类型、token*/
    config.headers.Authorization = auth.token_type + ' ' + auth.token
    /*判断刷新token请求的refresh_token是否过期*/
    if (util.isRefreshTokenExpired()) {
     alert('刷新token过期,请重新登录')
     /*清除本地保存的auth*/
     localStorage.removeItem('auth')
     window.location.href = '#/login'
     return
    }
    /*判断token是否将要过期*/
    if (util.isTokenExpired() && config.url.indexOf('admin/auth/current') === -1) {
     /*判断是否正在刷新*/
     if (!window.isRefreshing) {
      /*将刷新token的标志置为true*/
      window.isRefreshing = true
      /*发起刷新token的请求*/
      apiList.refreshToken({refresh_token: getRefreshToken()}).then(res => {
       /*将标志置为false*/
       window.isRefreshing = false
       /*成功刷新token*/
       config.headers.Authorization = res.data.data.token_type + ' ' + res.data.data.token
       /*更新auth*/
       localStorage.setItem('auth', JSON.stringify(res.data.data))
       /*执行数组里的函数,重新发起被挂起的请求*/
       onRrefreshed(res.data.data.token)
       /*执行onRefreshed函数后清空数组中保存的请求*/
       refreshSubscribers = []
      }).catch(err => {
       alert(err.response.data.message)
       /*清除本地保存的auth*/
       // localStorage.removeItem('auth')
       window.location.href = '#/login'
      })
     }
     /*把请求(token)=>{....}都push到一个数组中*/
     let retry = new Promise((resolve, reject) => {
      /*(token) => {...}这个函数就是回调函数*/
      subscribeTokenRefresh((token) => {
       config.headers.Authorization = 'Bearer ' + token
       /*将请求挂起*/
       resolve(config)
      })
     })
     return retry
    }
   }
   return config

  } else {
   /*未登录直接返回配置信息*/
   return config
  }
 },
 /*错误操作*/
 err => {
  return Promise.reject(err)
 }
)

这里需要注意几点:

1、当token即将过期或者已过期时,原则上,我们只需要有一个接口去触发刷新token的请求即可,这里的isRefreshing 变量,就起到这样一个监控的作用,它相当于一把锁,当刷新token的操作被触发后,其他的触发操作就被排斥在外了。

window.isRefreshing = false

2、刷新token的接口,用到了一个另外的token(refresh_token),这也是出于安全性考虑的,并且它也有过期时间,不过这个过期时间一般都比普通token的过期时间要长,所以在上面代码中,会发现,我在请求拦截中优先判断了refresh_token是否过期,如果过期则直接退出登录,不再进行下一步的操作。

/*判断刷新token请求的refresh_token是否过期*/
if (util.isRefreshTokenExpired() && config.url.indexOf('admin/auth/current') === -1) {
 alert('刷新token过期,请重新登录')
 /*清除本地保存的auth*/
 localStorage.removeItem('auth')
 window.location.href = '#/login'
 return
}

3、在触发了刷新token的操作后,我们还需要先将其他的请求挂起,在获取新的token之后再重新发起这些请求。

/*把请求(token)=>{....}都push到一个数组中*/
let retry = new Promise((resolve, reject) => {
 /*(token) => {...}这个函数就是回调函数*/
 subscribeTokenRefresh((token) => {
  config.headers.Authorization = 'Bearer ' + token
  /*将请求挂起*/
  resolve(config)
 })
})
return retry

在刷新token请求的成功回调里执行下面代码,重新发起请求。

/*执行数组里的函数,重新发起被挂起的请求*/
 onRrefreshed(res.data.data.token)

4、因为有人在评论里问util文件,应该是想知道具体怎么判断token过期的,其实在获得token时,是有返回一个token过期时间 ,你可以先将它先保存起来,然后在需要时,拿出来与本地时间比较即可

/*判断token是否过期*/
function isTokenExpired() {
 /*从localStorage中取出token过期时间*/
 let expiredTime = new Date(JSON.parse(localStorage.auth).expired_at).getTime() / 1000
 /*获取本地时间*/
 let nowTime = new Date().getTime() / 1000
 /*获取校验时间差*/
 let diffTime = JSON.parse(sessionStorage.diffTime)
 /*校验本地时间*/
 nowTime -= diffTime
 /*如果 < 10分钟,则说明即将过期*/
 return (expiredTime - nowTime) < 10*60
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery maxlength文本字数限制插件
Apr 16 Javascript
js实现幻灯片播放图片示例代码
Nov 07 Javascript
js获取 type=radio 值的方法
May 09 Javascript
jquery 设置style:display的方法
Jan 29 Javascript
js判断当前页面用什么浏览器打开的方法
Jan 06 Javascript
jQuery实现图片加载完成后改变图片大小的方法
Mar 29 Javascript
BootStrap日期控件在模态框中选择时间下拉菜单无效的原因及解决办法(火狐下不能点击)
Aug 18 Javascript
JS设计模式之策略模式概念与用法分析
Feb 05 Javascript
在Vue项目中引入腾讯验证码服务的教程
Apr 03 Javascript
vue实现拖拽的简单案例 不超出可视区域
Jul 25 Javascript
create-react-app中添加less支持的实现
Nov 15 Javascript
微信小程序开发之获取用户手机号码(php接口解密)
May 17 Javascript
vue 权限认证token的实现方法
Jul 17 #Javascript
vue 实现axios拦截、页面跳转和token 验证
Jul 17 #Javascript
详解webpack import()动态加载模块踩坑
Jul 17 #Javascript
vue-router中的hash和history两种模式的区别
Jul 17 #Javascript
JS使用tween.js动画库实现轮播图并且有切换功能
Jul 17 #Javascript
SVG实现时钟效果
Jul 17 #Javascript
JS中实现隐藏部分姓名或者电话号码的代码
Jul 17 #Javascript
You might like
php操作xml入门之xml基本介绍及xml标签元素
2015/01/23 PHP
PHP中非常有用却鲜有人知的函数集锦
2019/08/17 PHP
Jquery实现侧边栏跟随滚动条固定(兼容IE6)
2014/04/02 Javascript
javascript实现图片跟随鼠标移动效果的方法
2015/05/13 Javascript
Bootstrap每天必学之js插件
2015/11/30 Javascript
Jquery 自定义事件实现发布/订阅的简单实例
2016/06/12 Javascript
Node.js+Express+MySql实现用户登录注册功能
2017/07/10 Javascript
javaScript实现复选框全选反选事件详解
2020/11/20 Javascript
Vue使用vux-ui自定义表单验证遇到的问题及解决方法
2018/05/10 Javascript
vue组件实现进度条效果
2018/06/06 Javascript
微信小程序实现默认第一个选中变色效果
2018/07/17 Javascript
微信小程序实现顶部下拉菜单栏
2018/11/04 Javascript
Vue中Table组件Select的勾选和取消勾选事件详解
2019/03/19 Javascript
纯javascript实现选择框的全选与反选功能
2019/04/08 Javascript
解决vue-cli@3.xx安装不成功的问题及搭建ts-vue项目
2020/02/09 Javascript
js通过canvas生成图片缩略图
2020/10/02 Javascript
[02:58]献给西雅图的情书_高清
2014/05/29 DOTA
python利用hook技术破解https的实例代码
2013/03/25 Python
Python下的twisted框架入门指引
2015/04/15 Python
Python函数可变参数定义及其参数传递方式实例详解
2015/05/25 Python
python把数组中的数字每行打印3个并保存在文档中的方法
2018/07/17 Python
ipad上运行python的方法步骤
2019/10/12 Python
Python计算公交发车时间的完整代码
2020/02/12 Python
django admin 添加自定义链接方式
2020/03/11 Python
利用python下载scihub成文献为PDF操作
2020/07/09 Python
H5页面适配iPhoneX(就是那么简单)
2019/12/02 HTML / CSS
Luxplus丹麦:香水和个人护理折扣
2018/04/23 全球购物
北京某科技有限公司C# .net笔试题
2014/09/27 面试题
摄影实习自我鉴定
2013/09/20 职场文书
市场营销调查计划书
2014/05/02 职场文书
锦旗标语大全
2014/06/23 职场文书
工伤事故赔偿协议书范文
2014/09/24 职场文书
群众路线自查自纠工作情况报告
2014/10/28 职场文书
2015会计试用期工作总结
2014/12/12 职场文书
尼克胡哲观后感
2015/06/08 职场文书
Redis实现订单过期删除的方法步骤
2022/06/05 Redis