From 880148d6799c9742df7d196a135e644be49037b3 Mon Sep 17 00:00:00 2001 From: mlogclub Date: Thu, 30 Apr 2026 18:10:01 +0800 Subject: [PATCH] fix(web): sync auth expiry state --- web/components/auth-provider.tsx | 32 ++++++++++++++++++++++++++------ web/lib/api/client.ts | 4 ++-- web/lib/auth.ts | 9 +++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/web/components/auth-provider.tsx b/web/components/auth-provider.tsx index 3e8e877..f72fbc4 100644 --- a/web/components/auth-provider.tsx +++ b/web/components/auth-provider.tsx @@ -13,6 +13,7 @@ import { usePathname, useRouter } from "next/navigation" import { fetchProfile, logout } from "@/lib/api/auth" import { + AUTH_SESSION_EXPIRED_EVENT, clearSession, readSession, writeSession, @@ -68,16 +69,35 @@ export function AuthProvider({ children }: { children: ReactNode }) { }, [requiresAuth, router]) async function signOut() { - await logout() - setSession(null) - startTransition(() => { - router.replace("/dashboard/login") - }) + try { + await logout() + } finally { + setSession(null) + startTransition(() => { + router.replace("/dashboard/login") + }) + } } + useEffect(() => { + function handleAuthExpired() { + setSession(null) + if (requiresAuth) { + startTransition(() => { + router.replace("/dashboard/login") + }) + } + } + + window.addEventListener(AUTH_SESSION_EXPIRED_EVENT, handleAuthExpired) + return () => { + window.removeEventListener(AUTH_SESSION_EXPIRED_EVENT, handleAuthExpired) + } + }, [requiresAuth, router]) + useEffect(() => { const stored = readSession() - setSession(stored) + setSession(stored) if (stored) { void refreshProfile() return diff --git a/web/lib/api/client.ts b/web/lib/api/client.ts index beb1646..56a4daf 100644 --- a/web/lib/api/client.ts +++ b/web/lib/api/client.ts @@ -1,4 +1,4 @@ -import { clearSession, readSession } from "@/lib/auth" +import { expireSession, readSession } from "@/lib/auth" const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL?.trim() || "" @@ -20,7 +20,7 @@ async function parseResult(response: Response) { const payload = (await response.json()) as JsonResult if (!response.ok || !payload.success) { if (payload.errorCode === 3000 || payload.errorCode === 3002) { - clearSession() + expireSession() } const error = new Error(payload.message || "请求失败") ;(error as Error & { errorCode?: number }).errorCode = payload.errorCode diff --git a/web/lib/auth.ts b/web/lib/auth.ts index d944a18..e59d8cf 100644 --- a/web/lib/auth.ts +++ b/web/lib/auth.ts @@ -16,6 +16,7 @@ export type AuthSession = { } const SESSION_STORAGE_KEY = "cs-ai-agent-session" +export const AUTH_SESSION_EXPIRED_EVENT = "cs-ai-agent-auth-expired" function hasWindow() { return typeof window !== "undefined" @@ -52,3 +53,11 @@ export function clearSession() { } window.localStorage.removeItem(SESSION_STORAGE_KEY) } + +export function expireSession() { + if (!hasWindow()) { + return + } + clearSession() + window.dispatchEvent(new Event(AUTH_SESSION_EXPIRED_EVENT)) +}