import { useCallback, useState } from 'react' import { login as loginRequest } from '../api/auth' // storage 键:登录态写在浏览器。 // - 勾“记住我” → localStorage(关浏览器再开仍登录) // - 不勾 → sessionStorage(刷新仍在,关标签页/浏览器即清) const STORAGE_KEY = 'ip.auth' interface Session { username: string token: string } function parseSession(raw: string | null): Session | null { if (!raw) return null try { const parsed = JSON.parse(raw) as Partial if (typeof parsed.username === 'string' && typeof parsed.token === 'string') { return { username: parsed.username, token: parsed.token } } } catch { // 解析失败(被手动改坏等)当作未登录 } return null } // 先读 localStorage(记住我),再读 sessionStorage(仅本次会话)。 function loadSession(): Session | null { return ( parseSession(localStorage.getItem(STORAGE_KEY)) ?? parseSession(sessionStorage.getItem(STORAGE_KEY)) ) } export interface Auth { /** 已登录则为当前用户名,否则为 null */ username: string | null /** 当前会话 token(JWT),未登录为 null。用于受保护接口的 Authorization 头 */ token: string | null /** 校验凭据;remember 为 true 时持久化到 localStorage,否则只存 sessionStorage */ signIn: (username: string, password: string, remember: boolean) => Promise /** 退出登录并清除浏览器里的会话(两种 storage 都清) */ signOut: () => void } /** * 登录态管理。初始值从 localStorage / sessionStorage 恢复, * 因此刷新页面后仍停留在登录后界面(“记住我”决定关浏览器后是否还在)。 */ export function useAuth(): Auth { const [session, setSession] = useState(loadSession) const signIn = useCallback( async (username: string, password: string, remember: boolean) => { const result = await loginRequest(username, password) const next: Session = { username: result.username, token: result.token } setSession(next) const raw = JSON.stringify(next) if (remember) { // 记住我:持久化,关浏览器再开仍登录。 localStorage.setItem(STORAGE_KEY, raw) sessionStorage.removeItem(STORAGE_KEY) } else { // 不记住:仅本次会话,刷新仍在、关标签页/浏览器即清。 sessionStorage.setItem(STORAGE_KEY, raw) localStorage.removeItem(STORAGE_KEY) } }, [], ) const signOut = useCallback(() => { setSession(null) localStorage.removeItem(STORAGE_KEY) sessionStorage.removeItem(STORAGE_KEY) }, []) return { username: session?.username ?? null, token: session?.token ?? null, signIn, signOut } }