Files
HeXi/hexi/web/src/auth/auth.tsx
T
sansenhoshiandClaude Code c53b210413 feat: revamp web hub — global connection status, array config editor, log streaming
- Global connection badge in app header (persistent dashboard SSE via ConnectionProvider)
- LogProvider keeps log data and SSE stream alive across page switches (no reload spinner)
- Config drawer: password reveal toggle, array-type row editor for list fields
- Plugin management: optimistic updates, race-free loading, reset all group overrides
- Logs: load-earlier pagination; backend tail-read optimization (before/end offsets)
- web_auth: Web password changes persist (sync_admin seeding only when .env has explicit key)
- Dashboard: collect in thread pool + 1s result cache
- ErrorBoundary + local Suspense: plugin chunk loading stays inside content area
- UI polish: table row hover, mobile header/breadcrumb fixes, wider config drawer
- config_standard: array type inference for list fields; array env skip
- random_jm_code / steam_info: array schema migration; README web frontend note

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-03 15:39:10 +08:00

45 lines
1.6 KiB
TypeScript

import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'
import { authLogin, authLogout, AUTH_EXPIRED_EVENT, clearSession, getUserName, setSession, TOKEN_KEY, USER_KEY } from '../api/client'
interface AuthState {
token: string
username: string
login: (u: string, p: string) => Promise<void>
logout: () => void
}
const Ctx = createContext<AuthState>({ token: '', username: '', login: async () => {}, logout: () => {} })
export function AuthProvider({ children }: { children: ReactNode }) {
const [token, setToken] = useState(() => localStorage.getItem(TOKEN_KEY) || '')
const [username, setUsername] = useState(() => localStorage.getItem(USER_KEY) || '')
const login = async (u: string, p: string) => {
const data = await authLogin(u, p)
setSession(data.token, data.username)
setToken(data.token)
setUsername(data.username)
}
const logout = () => {
// 先吊销服务端令牌(fire-and-forget,失败不阻塞退出),再清理本地
authLogout().catch(() => {})
clearSession()
setToken('')
setUsername('')
}
// 任何请求命中 401(登录态无效/过期)时,同步清空内存态,
// AppLayout 会立即自动跳转到登录页。
useEffect(() => {
const onExpired = () => {
clearSession()
setToken('')
setUsername('')
}
window.addEventListener(AUTH_EXPIRED_EVENT, onExpired)
return () => window.removeEventListener(AUTH_EXPIRED_EVENT, onExpired)
}, [])
return <Ctx.Provider value={{ token, username, login, logout }}>{children}</Ctx.Provider>
}
export const useAuth = () => useContext(Ctx)