vue axios 刷新token 刷新jwt js刷新token http刷新token

前言 在互联网的登录系统中通常有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已经能够了.有问题的小伙伴请求留言.