问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Vue3 + Axios双Token刷新解决方案

创作时间:
作者:
@小白创作中心

Vue3 + Axios双Token刷新解决方案

引用
CSDN
1.
https://m.blog.csdn.net/qq_56046190/article/details/141710796

在现代前端开发中,使用API进行数据交互时,我们常常会遇到身份认证的问题。为了提高安全性,许多应用采用了Token机制,如JWT(JSON Web Token)来管理用户的身份状态。本文将介绍如何在Vue3项目中使用Axios实现双Token刷新机制,确保用户体验流畅的同时提高安全性。

前置条件

  1. 本文只针对Vue3前端所编写的双Token刷新解决方案,关于Spring Cloud微服务项目的双Token刷新实现,请参考:Spring Cloud + JWT实现双Token刷新
  2. 关于Vue3项目的搭建,请参考:Vite 创建 Vue3 + TS 项目
  3. 本文将通过封装Axios的方式,让前端实现无感刷新Token,关于Axios的封装,请参考:Vue3项目基于Axios封装request请求

刷新机制

在完成上述步骤后,我们就可以开始对前端项目进行操作了。但首先,我们需要了解到双Token刷新的机制:

在使用 Token 认证时,我们通常会使用两种Token:

  1. Access Token:用于身份验证,通常时效较短(如 10 分钟)。
  2. Refresh Token:用于获取新的 Access Token,时效较长(如 7 天至几个月)。

当Access Token过期时,我们可以使用Refresh Token来请求新的Access Token,而不是要求用户重新登录。通过这种方式,用户的体验将更加平滑。

但是,这里是博主自己写的后端,博主的服务端在双Token刷新机制上的原理跟上述是一样的, 不同的是,博主在生成Token的时候,并没有将Refresh Token返回给前端,而是跟UserId一起以键值对的形式存储在了Redis中。

在客户端Access Token过期后,直接根据Base64解析出Access Token载荷中的UserId,然后根据这个UserId查询存储在Redis中的Refresh Token,如果这个Refresh Token有效且是合法的,那么我们就根据之前Access Token载荷中的信息重新生成一个Access Token返回给客户端,以此来达到刷新Token的目的。

根据以上Token刷新机制,我们在Vue3前端代码中,可以给出一个无感刷新Token的思路:

  • 如果Access Token过期,那么我们可以通过Axios的响应拦截器获取到新的Access Token
  • 如果获取到的这个Access Token存在且不为空,我们可以重新发送原始请求

代码实现

// 添加响应拦截器
service.interceptors.response.use(
    async (response) => {
        // 判断是否有新的Token
        if (response.data.ACCESS_TOKEN) {
            // 将服务端返回的新Token存储到Session中
            Session.set('token', response.data.ACCESS_TOKEN);
            // 重新发送原始请求
            const config = response.config;
            try {
                const newResponse = await service.request(config);
                return newResponse;
            } catch (error) {
                return Promise.reject(error);
            }
        }
        // 对响应数据做点什么
        const res = response.data;
        if (res.code && res.code !== 0) {
            // `token` 过期或者账号已在别处登录
            if (res.code === 401 || res.code === 4001) {
                Session.clear(); // 清除浏览器全部临时缓存
                window.location.href = '/'; // 去登录页
                ElMessageBox.alert('你已被登出,请重新登录', '提示', {})
                    .then(() => { })
                    .catch(() => { });
                return Promise.reject(service.interceptors.response);
            } else {   // 如果响应中有新的 token,则更新 Session 中的 token
                return res;
            }
        } else {
            return res;
        }
    },
    (error) => {
        // 对响应错误做点什么
        if (error.message.indexOf('timeout') != -1) {
            ElMessage.error('网络超时');
        } else if (error.message == 'Network Error') {
            ElMessage.error('网络连接错误');
        } else {
            if (error.response.data) ElMessage.error(error.response.statusText);
            else ElMessage.error('接口路径找不到');
        }
        return Promise.reject(error);
    }
);  

检验真理

如图,当Token过期时,我们访问这个查询接口时,Axios进行了两次接口调用
第一次调用这个查询接口时,我们的Token失效了,拿到了服务端给的新的Token
然后,根据我们之前在Axios响应拦截器中的代码逻辑,它在将这个新的Token存储到Session中后,又重新发送了一次原始请求

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号