fix(auth): use auth.logout() instead of localStorage.removeItem in interceptors

When a 401/expired-token fires in client.ts or file.ts, the handlers were
clearing localStorage but not the Pinia auth.token ref. The route guard
reads Pinia, so router.push('/login') was immediately bounced back to
/dashboard, leaving the user in a ghost-authenticated state where all API
calls failed with 401.

Calling auth.logout() clears both Pinia state and localStorage atomically,
so the route guard correctly allows the redirect to /login.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
这个提交包含在:
XuqmGroup 2026-05-18 14:12:03 +08:00
父节点 eba5133fed
当前提交 7d100a9efc
共有 2 个文件被更改,包括 6 次插入4 次删除

查看文件

@ -2,6 +2,7 @@ import axios from 'axios'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import router from '@/router' import router from '@/router'
import { isJwtExpired } from '@/utils/jwt' import { isJwtExpired } from '@/utils/jwt'
import { useAuthStore } from '@/stores/auth'
const client = axios.create({ const client = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL ?? '/api', baseURL: import.meta.env.VITE_API_BASE_URL ?? '/api',
@ -31,7 +32,7 @@ client.interceptors.request.use((config) => {
if (token && !isJwtExpired(token)) { if (token && !isJwtExpired(token)) {
config.headers.Authorization = `Bearer ${token}` config.headers.Authorization = `Bearer ${token}`
} else if (token && isJwtExpired(token)) { } else if (token && isJwtExpired(token)) {
localStorage.removeItem('token') useAuthStore().logout()
if (router.currentRoute.value.path !== '/login') { if (router.currentRoute.value.path !== '/login') {
router.push('/login?reason=' + encodeURIComponent('登录已失效,请重新登录')) router.push('/login?reason=' + encodeURIComponent('登录已失效,请重新登录'))
} }
@ -41,7 +42,7 @@ client.interceptors.request.use((config) => {
}) })
function handleAuthFailure(message: string) { function handleAuthFailure(message: string) {
localStorage.removeItem('token') useAuthStore().logout()
if (router.currentRoute.value.path !== '/login') { if (router.currentRoute.value.path !== '/login') {
router.push('/login') router.push('/login')
} }

查看文件

@ -2,6 +2,7 @@ import axios from 'axios'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import router from '@/router' import router from '@/router'
import { isJwtExpired } from '@/utils/jwt' import { isJwtExpired } from '@/utils/jwt'
import { useAuthStore } from '@/stores/auth'
export type UploadProgressHandler = (percent: number) => void export type UploadProgressHandler = (percent: number) => void
@ -33,7 +34,7 @@ fileClient.interceptors.request.use((config) => {
if (token && !isJwtExpired(token)) { if (token && !isJwtExpired(token)) {
config.headers.Authorization = `Bearer ${token}` config.headers.Authorization = `Bearer ${token}`
} else if (token && isJwtExpired(token)) { } else if (token && isJwtExpired(token)) {
localStorage.removeItem('token') useAuthStore().logout()
if (router.currentRoute.value.path !== '/login') { if (router.currentRoute.value.path !== '/login') {
router.push('/login?reason=' + encodeURIComponent('登录已失效,请重新登录')) router.push('/login?reason=' + encodeURIComponent('登录已失效,请重新登录'))
} }
@ -47,7 +48,7 @@ fileClient.interceptors.response.use(
(error) => { (error) => {
const status = error.response?.status const status = error.response?.status
if (status === 401) { if (status === 401) {
localStorage.removeItem('token') useAuthStore().logout()
if (router.currentRoute.value.path !== '/login') { if (router.currentRoute.value.path !== '/login') {
router.push('/login') router.push('/login')
} }