auto logout on cookie expiration
This commit is contained in:
parent
3ce344f969
commit
19bd8ff104
@ -21,6 +21,9 @@ app.use(createPinia())
|
||||
app.use(router)
|
||||
app.use(naive)
|
||||
|
||||
// 初始化fetch拦截器(需要在pinia初始化之后)
|
||||
import '../shared/utils/fetchInterceptor'
|
||||
|
||||
// 初始化认证状态
|
||||
import { useAuthStore } from '../shared/stores/auth'
|
||||
const authStore = useAuthStore()
|
||||
|
||||
@ -183,7 +183,7 @@ const router = createRouter({
|
||||
router.beforeEach(async (to, _from, next) => {
|
||||
const authStore = useAuthStore()
|
||||
|
||||
// 初始化认证状态
|
||||
// 初始化认证状态(内部会检查cookie是否过期)
|
||||
if (!authStore.isAuthenticated) {
|
||||
await authStore.initAuth()
|
||||
}
|
||||
|
||||
@ -27,6 +27,14 @@ export function getSessionCookie(): string | null {
|
||||
return cookies.get('sid')
|
||||
}
|
||||
|
||||
// 检查cookie是否过期(通过检查session cookie是否存在)
|
||||
export function isCookieExpired(): boolean {
|
||||
const sessionCookie = getSessionCookie()
|
||||
const sessionUser = getSessionUser()
|
||||
// 如果session cookie或user_id不存在,认为cookie已过期
|
||||
return !sessionCookie || !sessionUser
|
||||
}
|
||||
|
||||
export const loginApi = async (username: string, password: string): Promise<LoginResponse> => {
|
||||
const response = await fetch(`/jingrow/login`, {
|
||||
method: 'POST',
|
||||
@ -67,6 +75,13 @@ export const getUserInfoApi = async (): Promise<UserInfo> => {
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
// 401或403表示cookie过期或未授权
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
const error = new Error('Cookie已过期,请重新登录')
|
||||
// @ts-ignore
|
||||
error.status = response.status
|
||||
throw error
|
||||
}
|
||||
const errorData = await response.json().catch(() => ({}))
|
||||
throw new Error(errorData.detail || errorData.message || '获取用户信息失败')
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { loginApi, getUserInfoApi, logoutApi, getSessionUser } from '../api/auth'
|
||||
import { loginApi, getUserInfoApi, logoutApi, getSessionUser, isCookieExpired } from '../api/auth'
|
||||
|
||||
export interface User {
|
||||
id: string
|
||||
@ -59,6 +59,15 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
}
|
||||
|
||||
const initAuth = async () => {
|
||||
// 首先检查Cookie是否过期
|
||||
if (isCookieExpired()) {
|
||||
// Cookie已过期,清除本地状态
|
||||
if (isAuthenticated.value) {
|
||||
await logout()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 首先检查Cookie中的session
|
||||
const sessionUser = getSessionUser()
|
||||
if (sessionUser) {
|
||||
@ -72,8 +81,12 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
localStorage.setItem('jingrow_user', JSON.stringify(userInfo))
|
||||
localStorage.setItem('jingrow_authenticated', 'true')
|
||||
return
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('验证用户信息失败:', error)
|
||||
// 如果是401/403错误,说明cookie已过期
|
||||
if (error.status === 401 || error.status === 403 || error.message?.includes('过期')) {
|
||||
await logout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +102,14 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
// 验证用户信息是否仍然有效
|
||||
const userInfo = await getUserInfoApi()
|
||||
user.value = userInfo
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('验证用户信息失败:', error)
|
||||
logout()
|
||||
// 如果是401/403错误,说明cookie已过期
|
||||
if (error.status === 401 || error.status === 403 || error.message?.includes('过期')) {
|
||||
await logout()
|
||||
} else {
|
||||
logout()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,8 +121,12 @@ export const useAuthStore = defineStore('auth', () => {
|
||||
const userInfo = await getUserInfoApi()
|
||||
user.value = userInfo
|
||||
localStorage.setItem('jingrow_user', JSON.stringify(userInfo))
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('更新用户信息失败:', error)
|
||||
// 如果是401/403错误,说明cookie已过期
|
||||
if (error.status === 401 || error.status === 403 || error.message?.includes('过期')) {
|
||||
await logout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
37
apps/jingrow/frontend/src/shared/utils/fetchInterceptor.ts
Normal file
37
apps/jingrow/frontend/src/shared/utils/fetchInterceptor.ts
Normal file
@ -0,0 +1,37 @@
|
||||
// 保存原始的fetch函数
|
||||
const originalFetch = window.fetch
|
||||
|
||||
// 包装fetch函数,添加401/403错误处理
|
||||
window.fetch = async function(...args: Parameters<typeof fetch>): Promise<Response> {
|
||||
const response = await originalFetch(...args)
|
||||
|
||||
// 检查响应状态码(仅在401/403时处理)
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
// 延迟导入,确保pinia已初始化
|
||||
try {
|
||||
const { useAuthStore } = await import('../stores/auth')
|
||||
const { default: router } = await import('../../app/router')
|
||||
const authStore = useAuthStore()
|
||||
|
||||
// 如果用户已登录,执行登出操作
|
||||
if (authStore.isLoggedIn) {
|
||||
console.warn('检测到401/403错误,Cookie已过期,自动退出登录')
|
||||
await authStore.logout()
|
||||
|
||||
// 跳转到登录页(避免重复跳转)
|
||||
if (router.currentRoute.value.path !== '/login') {
|
||||
router.push('/login')
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// 如果store还未初始化,忽略错误(应用启动阶段)
|
||||
// 这不会影响正常的API调用
|
||||
}
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
// 导出原始fetch(如果需要的话)
|
||||
export { originalFetch as originalFetch }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user