前言 在互联网的登录系统中通常有session cookie 和 jwt token来进行验证用户是否登陆的.下面来讲一下关于 jwt的坑:javascript
1.首先登陆成功的返回,其中jwt的有效期为2小时,refreshJwt的有效期为30天以下:前端
2.保存jwt 和refreshJwt 在cookie中,固然这里不必定要保存在cookie中,也能够保存在别的地方.这里以cookie为例子:java
3.核心思路:当jwt过时时(超过了2小时),调用后端接口会返回401的状态码(这个时候表明jwt已通过期了,须要刷新了),再拦截器中拦截响应的数据,这个时候就须要拿refreshJwt去调用后端的刷新接口,把获取到的最新jwt覆盖掉本地的jwt和refreshJwt,而后再次进行刚才的请求,而且把获取到的数据,从响应拦截器中返回回去.ios
步骤大概如此: 前端发起ajax请求 => 后端发现jwt已通过期,返回401状态码 => 前端拦截响应数据,并发起刷新token的请求 => 拿到最新的jwt和refresh,保存到本地 => 拿到最新的jwt去进行刚刚未请求成功的接口 => 获取到刚刚请求的结果,覆盖第一次请求失败(状态码为401)的响应数据 => 返回第二次请求的结果. ajax
另外一种状况就是:前端发起ajax请求 => 后端发现jwt已通过期,返回401状态码 => 前端拦截响应数据,并发起刷新token的请求 =>后端返回了410的状态码(这个时候表明refreshJwt也过时了,须要进行从新登陆了) => 真正的过时了,须要跳转到登陆界面. element-ui
这样刷新token是在用户无感的状况下进行操做的.axios
下面进行贴代码了:后端
此拦截器模块为http,封装的步骤参考:https://blog.csdn.net/qq_33270001/article/details/86612528 注:原来的http模块中并未封装refreshJwt的操做.cookie
3. 新建一个refreshToken.js的文件:网络
看核心操做就是,util.getCookie(`REFRESHJWT-COLLECTOR`); 这些都是封装来操做cookie的工具.无需重点关注
import axios from 'axios'; import router from '@/router/index'; import util from '@/common/method/util'; import { API_COMMON } from './models/types'; export default async() => { const refreshToken = util.getCookie(`REFRESHJWT-COLLECTOR`); try { const { code, data } = await axios.post(`${API_COMMON}/refreshJwt`, { refreshJwt: refreshToken }); if (code == 410) { return router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }); } else { const { jwt, refreshJwt } = data; if (jwt && refreshJwt) { util.setCookie(`TOKEN-COLLECTOR`, jwt); //jwt util.setCookie(`REFRESHJWT-COLLECTOR`, refreshJwt); //刷新token } } return { code, data }; } catch (error) { console.log(error); } };
4. 拦截器配置以下:
/*** * Created by Simple on 2018/1/14 0014. * Http请求控制器模块 */ import axios from 'axios'; import router from '@/router/index'; import conf from '@/common/base/config'; import util from '@/common/method/util'; import { Loading, Message } from 'element-ui'; import refreshToken from './refreshToken'; // axios 配置 axios.defaults.timeout = 1000 * 60 * 5; axios.defaults.baseURL = process.env.NODE_ENV === 'production' ? conf.productionUrl : conf.devUrl; // 配置通用请求动画 let loading = null; let isLock = true; /** * 通用请求拦截配置 * @param {*} config */ const axiosConf = (config) => { config.headers.Authorization = util.getCookie(`TOKEN-COLLECTOR`); loading = Loading.service({ lock: true, text: '拼命加载中...', background: 'rgba(255, 255, 255, .1)' }); return config; }; axios.interceptors.request.use(axiosConf, err => { if (loading) loading.close(); return Promise.reject(err); }); // http response 拦截器 axios.interceptors.response.use(async(response) => { let data = {}; if (response && response.data) { let code = Number(response.code || response.data.code); if (code === 401) { // 401 清除token信息并跳转到登陆页面 const refreshJwt = util.getCookie(`REFRESHJWT-COLLECTOR`); if ((refreshJwt != 'undefined' && refreshJwt) && isLock) { await refreshToken(response); isLock = false; //这里防止并发的时候形成死循环,因此要加锁 //刷新完成,继续以前的请求 response.config.headers.Authorization = util.getCookie(`TOKEN-COLLECTOR`); const result = await axios.request(axiosConf(response.config)); if (result) { data = result; isLock = true; } } else { Message.error(response.data && response.data.msg || `身份过时,请从新登陆!`); if (router.currentRoute.path != '/login') { setTimeout(() => { router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }); }, 1200); } } } else if (code === 200) { data = response.data; } else if (code === 403) { //无权限 Message.error(`无权访问!`); router.replace({ name: '/403', query: { redirect: router.currentRoute.fullPath } }); } else if (code === 410) { Message.error(`身份过时,请从新登陆!`); setTimeout(() => { router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }); }, 1200); } else { Message.error(response.data && response.data.msg || '网络链接出错!请稍后刷新重试!'); } } if (loading) loading.close(); return data; }, (error) => { console.log(`object`, error); if (loading) loading.close(); Message.error('哎呀~ (ಥ﹏ಥ)网络又开小差了,请稍后刷新重试!'); return Promise.reject(error.response.data); }); export default axios;
5. 操做演示:
已通过期了,须要进行刷新操做
进行刷新覆盖操做
从新进行请求,并覆盖掉原来的
大功告成,小生的刷新token思路如此,如阁下有更好的思路,方便分享,请留言哦,刷新token已经能够了.有问题的小伙伴请求留言.