fix(auth): auto-logout and redirect on 401

This commit is contained in:
2026-02-07 23:35:32 +08:00
parent 5f432998a3
commit f8955d8a6c

View File

@@ -1,3 +1,5 @@
import { useAuthStore } from '@/stores/auth'
export type ApiSuccess<T> = {
success: true
data: T
@@ -27,6 +29,35 @@ export class ApiError extends Error {
}
}
let lastUnauthorizedHandledAt = 0
function handleUnauthorized(token?: string | null) {
if (!token) return
if (typeof window === 'undefined') return
const now = Date.now()
if (now - lastUnauthorizedHandledAt < 1000) return
lastUnauthorizedHandledAt = now
try {
const auth = useAuthStore()
auth.logout()
} catch {
localStorage.removeItem('imageforge_auth')
}
if (window.location.pathname === '/login') {
return
}
const redirect = encodeURIComponent(`${window.location.pathname}${window.location.search}`)
window.location.replace(`/login?redirect=${redirect}`)
}
function createApiError(status: number, error: ApiFailure['error']) {
return new ApiError(error.code, status, error.message, error.request_id)
}
async function parseEnvelope<T>(res: Response): Promise<ApiEnvelope<T>> {
const text = await res.text()
if (!text) {
@@ -86,7 +117,11 @@ export async function apiJson<T>(
const envelope = await parseEnvelope<T>(res)
if (envelope.success) return envelope.data
throw new ApiError(envelope.error.code, res.status, envelope.error.message, envelope.error.request_id)
if (res.status === 401 || envelope.error.code === 'UNAUTHORIZED') {
handleUnauthorized(token)
}
throw createApiError(res.status, envelope.error)
}
export async function apiGet<T>(path: string, token?: string | null, init?: RequestInit): Promise<T> {
@@ -102,7 +137,11 @@ export async function apiGet<T>(path: string, token?: string | null, init?: Requ
const envelope = await parseEnvelope<T>(res)
if (envelope.success) return envelope.data
throw new ApiError(envelope.error.code, res.status, envelope.error.message, envelope.error.request_id)
if (res.status === 401 || envelope.error.code === 'UNAUTHORIZED') {
handleUnauthorized(token)
}
throw createApiError(res.status, envelope.error)
}
export async function apiMultipart<T>(
@@ -124,6 +163,9 @@ export async function apiMultipart<T>(
const envelope = await parseEnvelope<T>(res)
if (envelope.success) return envelope.data
throw new ApiError(envelope.error.code, res.status, envelope.error.message, envelope.error.request_id)
if (res.status === 401 || envelope.error.code === 'UNAUTHORIZED') {
handleUnauthorized(token)
}
throw createApiError(res.status, envelope.error)
}