使用vue3+ts+axios+pinia实现无感刷新
在 Vue 3 项目中,结合 TypeScript、Axios 和 Pinia 实现 无感刷新(Token 自动刷新) 是一种常见的需求。无感刷新的核心逻辑是:当用户的访问令牌(Access Token)过期时,自动使用刷新令牌(Refresh Token)获取新的访问令牌,而用户无需重新登录。
以下是实现无感刷新的详细步骤和代码示例。
- 项目初始化
确保项目已经安装以下依赖:
-
Vue 3
-
TypeScript
-
Axios
-
Pinia
- 创建 Pinia Store
使用 Pinia 管理用户的认证状态和令牌。
创建 Auth Store
// src/stores/authStore.ts
import { defineStore } from 'pinia';
import { ref } from 'vue';
export const useAuthStore = defineStore('auth', () => {
const accessToken = ref<string | null>(null);
const refreshToken = ref<string | null>(null);
// 设置令牌
const setTokens = (newAccessToken: string, newRefreshToken: string) => {
accessToken.value = newAccessToken;
refreshToken.value = newRefreshToken;
};
// 清除令牌
const clearTokens = () => {
accessToken.value = null;
refreshToken.value = null;
};
return {
accessToken,
refreshToken,
setTokens,
clearTokens,
};
});
- 配置 Axios 实例
创建一个 Axios 实例,并添加请求拦截器和响应拦截器,用于自动刷新令牌。
// src/utils/axiosInstance.ts
import axios from 'axios';
import { useAuthStore } from '@/stores/authStore';
const axiosInstance = axios.create({
baseURL: 'https://api.example.com',
});
// 请求拦截器:添加 Access Token
axiosInstance.interceptors.request.use((config) => {
const authStore = useAuthStore();
if (authStore.accessToken) {
config.headers.Authorization = `Bearer ${authStore.accessToken}`;
}
return config;
});
// 响应拦截器:处理 Token 过期
axiosInstance.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
// 如果响应状态码为 401 且未重试过
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
const authStore = useAuthStore();
if (authStore.refreshToken) {
try {
// 使用 Refresh Token 获取新的 Access Token
const response = await axios.post('/auth/refresh', {
refreshToken: authStore.refreshToken,
});
// 更新 Access Token
authStore.setTokens(response.data.accessToken, authStore.refreshToken);
// 重试原始请求
originalRequest.headers.Authorization = `Bearer ${response.data.accessToken}`;
return axiosInstance(originalRequest);
} catch (refreshError) {
// 刷新 Token 失败,清除令牌并跳转到登录页
authStore.clearTokens();
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
}
return Promise.reject(error);
}
);
export default axiosInstance;
- 实现登录和刷新 Token 的逻辑
在登录和刷新 Token 的逻辑中,更新 Pinia Store 中的令牌。
登录逻辑
// src/api/auth.ts
import axiosInstance from '@/utils/axiosInstance';
import { useAuthStore } from '@/stores/authStore';
export const login = async (email: string, password: string) => {
const response = await axiosInstance.post('/auth/login', { email, password });
const authStore = useAuthStore();
authStore.setTokens(response.data.accessToken, response.data.refreshToken);
};
刷新 Token 逻辑
// src/api/auth.ts
export const refreshToken = async () => {
const authStore = useAuthStore();
const response = await axiosInstance.post('/auth/refresh', {
refreshToken: authStore.refreshToken,
});
authStore.setTokens(response.data.accessToken, authStore.refreshToken);
};
- 在组件中使用
在登录组件中调用登录逻辑,并在需要认证的请求中使用 Axios 实例。
<template>
<div>
<input v-model="email" placeholder="Email" />
<input v-model="password" type="password" placeholder="Password" />
<button @click="handleLogin">Login</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { login } from '@/api/auth';
const email = ref('');
const password = ref('');
const handleLogin = async () => {
await login(email.value, password.value);
};
</script>
获取用户数据
<template>
<div>
<h1>User Profile</h1>
<p>{{ userData }}</p>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import axiosInstance from '@/utils/axiosInstance';
const userData = ref(null);
onMounted(async () => {
const response = await axiosInstance.get('/user/profile');
userData.value = response.data;
});
</script>
总结
通过结合 Vue 3、TypeScript、Axios 和 Pinia,可以实现无感刷新功能,具体步骤如下:
-
创建 Pinia Store:管理用户的认证状态和令牌。
-
配置 Axios 实例:添加请求拦截器和响应拦截器,自动刷新 Token。
-
实现登录和刷新 Token 逻辑:更新 Pinia Store 中的令牌。
-
在组件中使用:调用登录逻辑和认证请求。
通过无感刷新,可以提升用户体验,避免频繁重新登录。
更多vue相关插件及后台管理模板可访问vue admin reference,代码详情请访问github