vue的token刷新处理

前言

以token处理登录的web系统,一般会有两个token:access-token和refresh-token。

node.js中,一般用jsonwebtoken这个模块。

access-token,是用户输入登录的账号密码,后台去db验证然后颁发的,它一般记录在浏览器的cookie中,并在浏览器关闭时自动删除,页面访问或ajax访问会自动通过cookie传回到后台,后台直接内存中校验,不用访问db,所以效率高;为了在access-token泄漏后及时止损,一般access-token会设置一个有效期,如1-8小时。

access-token设置了有效期后,过期了怎么办?为了及时止损,有效期不能设置太长,过期是一定会遇到的,比如工作狂,如果有效期设置的是8小时,他开着浏览器工作12小时,费力断断续续花了1个小时(电话多,喝咖啡尿多)打了张订单,提交时token过期了。再比如某些大屏幕展示的页面,可能连续几天几月的开着。遇到过期怎么办?

  1. 重定向到登录页面,用户输入账号密码登录后,再自动跳回订单页面,之前的资料都丢了,用户骂一句“靠”忍气吞声重新打。如果每天遇到一次,可能还可以忍。如果有效期太短,如1小时,每天遇到5,6次,那用户可能不干了,这时你可能要把未提交的订单资料暂时存到localstorage里面。
  2. 弹出登录框。登录框内容和代码如何做,预先就加载了,每个页面都有这部分,感觉很浪费,因为大部分时间用不上,动态从后台加载,可能不好实现。
  3. 登录后把账号密码记录在浏览器中,自动登录。但基于安全考虑,一般是用户特别勾选“记住我”,才会加密记录账号密码到localstorage中,用户下次打开浏览器时自动登录。如果token过期就自动登录,如何及时止损?后台修改密码或禁用账号,如何同步到前端的localstorage中。大部分app是这么干的。以上3种都是要再次去后台数据库验证,所以token过期时间不能太短,否则效率很差。
  4. 设置refresh-token机制,颁发access-token时同时颁发一个refresh-token,唯一区别是refresh-token有效期比较长,比如1个月。当access-token过期后,拿着refresh-token到后台换取新的access-token。通过在后台为refresh-token设置黑名单来及时止损,所以有黑名单的时候,可能效率也会一样的差。refresh-token也过期后,那就只有老老实实的让用户输入账号密码登录了,就是前面的1,2方法。因为refresh-token不常用,所以最好不要放在cookie中避免每次自动传到后台,放在localstorage较好。
    刷新access-token过程,如何让用户没感觉?思路是:发现access-token,自动用refresh-token去刷新,然后再自动跳到原来页面或者自动调用一次原来的ajax。

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
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/406906.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我对CSS vertical-align的一些理解与认识(二)

1. 我对不同浏览器解析vertical-align属性的理解 在上集中&#xff0c;在最后提供的实例中&#xff0c;vertical-align:middle实际上应该是与后面的文字是独立的&#xff0c;毫无关联&#xff0c;就是说vertical-align无论是什么&#xff0c;都不影响文字在box中的位置&#x…

request_do?send方法

Ruby中 respond_to? 和 send 的用法php?nameRuby" class"t_tag">Ruby中 respond_to? 和 send 的用法[收藏] Ruby中的字符串与符号 如同其他的OO语言一样&#xff0c;在ruby中&#xff0c;通过给对象发送消息&#xff0c;来完成对象的功能&#xff0c;比如…

Vue中token刷新及token过期的实现

总&#xff1a;通过axios&#xff0c;vuex&#xff0c;及自定义的方法实现。 以下是思路&#xff1a; 1.做token刷新必不可少的是&#xff0c;token&#xff08;请求时的token&#xff09; / refresh_token&#xff08;刷新token时用的refresh_token&#xff09; / resetTime&a…

Source Code Library 源代码收集器

对于程序员来说&#xff0c;收集、整理一些常用的源代码是经常性的工作&#xff0c;但很多时候&#xff0c;随着收集的代码、文档、压缩包的增长&#xff0c;也会产生另一个问题&#xff1a;那就是如何快速找到所需要的内容。 这个问题曾经困扰着我&#xff0c;后来我开始使用&…

VC2010如何给ActiveX添加事件

利用VC开发ActiveX时&#xff0c;需要给控件添加标准事件或自定义事件&#xff0c;在VC6中有多种方法&#xff1a; 一、按Ctrl W 打开类向导&#xff0d;&#xff1e;切换到“ActiveX Events"&#xff0d;&#xff1e;Add Event...&#xff0c;如图&#xff1a; 二、右…

css动态设置宽高

css 中可以使用 calc() 来动态设置宽高&#xff0c;但是&#xff0c;在表达式中运算符的前后必须要有空格 height:calc(100vh - 80px);

Windows Runtime (RT)

学了sl for wp 开发了1年都没入门&#xff0c;只能说自己的学习欲望太低了。 今天偶然才发现wrt 跟 .net 是2个东西... orz。 得抛弃 sl &#xff0c;wrt才是未来的主流吧... 这篇文章不错 http://www.dotblogs.com.tw/regionbbs/archive/2011/09/18/introducing.windows.runti…

产业链没有阴谋

IBM将PC甩给联想&#xff0c;是IBM的产业链阴谋吗&#xff1f;上个星期在客户的研讨会上有人这样问我。提问的这位朋友刚刚看过郎咸平的《产业链阴谋》&#xff0c;认为我们之所以处于“6 1”的低端&#xff0c;就是中了跨国公司的诡计&#xff0c;他们想进入高端&#xff0c;…

CSS中height:100%和height:inherit的异同

1. height:100%和height:inherit的异同 1.1 兼容性差异 height:100% IE6 √ height:inherit IE8 √ 1.2 大多数情况作用是一样的 除去兼容性&#xff0c;大多数情况下&#xff0c;两者作用是一样的&#xff0c;甚至都很难想出不一样的理由 父容器height: auto&#xff0c…

手机端双击页面放大的问题

制作手机端页面的时候我们都会加入一个meta标签&#xff0c; 该meta标签的作用是让当前viewport的宽度等于设备的宽度&#xff0c;同时不允许用户手动缩放。 其中 maximum-scale为允许用户的最大缩放值&#xff0c;user-scalable为是否允许用户进行缩放&#xff0c;yes(默认)…

cxxtest单元测试框架源码分析(二):所有对外功能实现分析

CxxTest的大部分诊断功能都是通过宏定义实现的&#xff0c;而且这部分的定义以及所有测试套的基类CxxTest:TestSuite定义和实现都在TestSuite.h和TestSuite.cpp里面。下面我们将通过分析这两个文件来分析CxxTest的对外功能体现。 1 //所有的类以及定义都是在CxxTest名称空间中2…

Interlocked.CompareExchange

class SourceManager { private SourceManager() { } private static SourceManager sourceManager; public static SourceManager Instance { get { if (sourceManager null) { /* lock 实现方式 功能与以下 Interlocked.CompareExchange 相同 lock (this) { if (sourceManag…

Dos下删除(非)空目录或文件

【删除非空文件夹】&#xff1a; 在xp中的虚拟dos也就是开始运行cmd啦&#xff0c;是可以输入中文的&#xff0c;要删除非空文件夹请用rmdir /s /q命令 删除非空目录&#xff1a;RMDIR [/S] [/Q] [drive:]path 删除空目录&#xff1a;RD [/S] [/Q] [drive:]path /S 除目录本…

absolute元素在text-align属性下的对齐显示

1. absolute元素是否可以响应text-align属性&#xff1f; 众所周知&#xff0c;text-align属性可以有效作用于inline/inline-block水平的元素&#xff0c;那么应用了position:absloute/fixed声明的元素呢&#xff1f; 上面效果中的图片就是应用了position: absolute声明&#…

vue-cli proxy中跨域中pathRewrite配置理解

1. vue本地项目调试线上接口出现跨域问题 2. 通过在 config/index.js 配置文件中找到proxyTable配置项 dev: {// PathsassetsSubDirectory: static,assetsPublicPath: /,proxyTable: {/api: {target: http://XX.XX.XX.XX:8083,changeOrigin: true,pathRewrite: {^/api: /api …

CSS3选择器:nth-child和:nth-of-type之间的差异

1. 深呼吸&#xff0c;直接内容 :nth-child和:nth-of-type都是CSS3中的伪类选择器&#xff0c;其作用近似却又不完全一样&#xff0c;对于不熟悉的人对其可能不是很区分&#xff0c;本文就将介绍两者的不同&#xff0c;以便于大家正确灵活使用这两类选择器 先看一个简单的实例…