Vue3 + Axios双Token刷新解决方案

        在现代前端开发中,使用 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中后,又重新发送了一次原始请求

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,你需要在后端实现一个登录接口,接口返回用户信息和 Token。 然后,你可以在 Vue3 项目中使用 Axios 发送登录请求,并将返回的 Token 存储到本地存储中,以便后续的请求可以使用该 Token 进行认证。 以下是一个简单的登录示例: 1. 在 Vue3 项目中安装 Axios:`npm install axios` 2. 创建登录页面,并添加表单元素和提交按钮 ```html <template> <div> <h2>登录</h2> <form @submit.prevent="login"> <label>用户名:</label> <input v-model="username" type="text" /> <br /> <label>密码:</label> <input v-model="password" type="password" /> <br /> <button type="submit">登录</button> </form> </div> </template> ``` 3. 在 Vue3 中,可以使用 `reactive` 函数创建响应式数据。在组件中创建一个对象,包含用户名和密码: ```javascript import { reactive } from 'vue'; export default { setup() { const formData = reactive({ username: '', password: '', }); return { formData, }; }, }; ``` 4. 在组件中添加 `login` 方法: ```javascript import { reactive } from 'vue'; import axios from 'axios'; export default { setup() { const formData = reactive({ username: '', password: '', }); const login = async () => { try { const response = await axios.post('/api/login', formData); localStorage.setItem('token', response.data.token); // 登录成功,跳转到首页 router.push('/home'); } catch (error) { console.error(error); } }; return { formData, login, }; }, }; ``` 5. 在路由守卫中判断用户是否已登录。如果没有登录,则跳转到登录页。 ```javascript import { createRouter, createWebHistory } from 'vue-router'; const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', name: 'Home', component: Home, meta: { // 添加路由元信息,用于判断该路由是否需要登录才能访问 requiresAuth: true, }, }, { path: '/login', name: 'Login', component: Login, }, ], }); router.beforeEach((to, from, next) => { const requiresAuth = to.matched.some((record) => record.meta.requiresAuth); const isAuthenticated = localStorage.getItem('token'); if (requiresAuth && !isAuthenticated) { next('/login'); } else { next(); } }); export default router; ``` 这样,你就可以实现一个简单的登录系统了。当用户访问需要登录才能访问的页面时,会先跳转到登录页面进行登录,登录成功后再跳转回目标页面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛*璃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值