fix(web): sync auth expiry state
This commit is contained in:
@@ -13,6 +13,7 @@ import { usePathname, useRouter } from "next/navigation"
|
|||||||
|
|
||||||
import { fetchProfile, logout } from "@/lib/api/auth"
|
import { fetchProfile, logout } from "@/lib/api/auth"
|
||||||
import {
|
import {
|
||||||
|
AUTH_SESSION_EXPIRED_EVENT,
|
||||||
clearSession,
|
clearSession,
|
||||||
readSession,
|
readSession,
|
||||||
writeSession,
|
writeSession,
|
||||||
@@ -68,16 +69,35 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|||||||
}, [requiresAuth, router])
|
}, [requiresAuth, router])
|
||||||
|
|
||||||
async function signOut() {
|
async function signOut() {
|
||||||
await logout()
|
try {
|
||||||
setSession(null)
|
await logout()
|
||||||
startTransition(() => {
|
} finally {
|
||||||
router.replace("/dashboard/login")
|
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(() => {
|
useEffect(() => {
|
||||||
const stored = readSession()
|
const stored = readSession()
|
||||||
setSession(stored)
|
setSession(stored)
|
||||||
if (stored) {
|
if (stored) {
|
||||||
void refreshProfile()
|
void refreshProfile()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { clearSession, readSession } from "@/lib/auth"
|
import { expireSession, readSession } from "@/lib/auth"
|
||||||
|
|
||||||
const API_BASE_URL =
|
const API_BASE_URL =
|
||||||
process.env.NEXT_PUBLIC_API_BASE_URL?.trim() || ""
|
process.env.NEXT_PUBLIC_API_BASE_URL?.trim() || ""
|
||||||
@@ -20,7 +20,7 @@ async function parseResult<T>(response: Response) {
|
|||||||
const payload = (await response.json()) as JsonResult<T>
|
const payload = (await response.json()) as JsonResult<T>
|
||||||
if (!response.ok || !payload.success) {
|
if (!response.ok || !payload.success) {
|
||||||
if (payload.errorCode === 3000 || payload.errorCode === 3002) {
|
if (payload.errorCode === 3000 || payload.errorCode === 3002) {
|
||||||
clearSession()
|
expireSession()
|
||||||
}
|
}
|
||||||
const error = new Error(payload.message || "请求失败")
|
const error = new Error(payload.message || "请求失败")
|
||||||
;(error as Error & { errorCode?: number }).errorCode = payload.errorCode
|
;(error as Error & { errorCode?: number }).errorCode = payload.errorCode
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export type AuthSession = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SESSION_STORAGE_KEY = "cs-ai-agent-session"
|
const SESSION_STORAGE_KEY = "cs-ai-agent-session"
|
||||||
|
export const AUTH_SESSION_EXPIRED_EVENT = "cs-ai-agent-auth-expired"
|
||||||
|
|
||||||
function hasWindow() {
|
function hasWindow() {
|
||||||
return typeof window !== "undefined"
|
return typeof window !== "undefined"
|
||||||
@@ -52,3 +53,11 @@ export function clearSession() {
|
|||||||
}
|
}
|
||||||
window.localStorage.removeItem(SESSION_STORAGE_KEY)
|
window.localStorage.removeItem(SESSION_STORAGE_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function expireSession() {
|
||||||
|
if (!hasWindow()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
clearSession()
|
||||||
|
window.dispatchEvent(new Event(AUTH_SESSION_EXPIRED_EVENT))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user