chore: initial project import
This commit is contained in:
commit
26620707a0
347 files changed
+56172
No files matched your search
@@ -0,0 +1,69 @@
|
||||
import { createContext, useCallback, useContext, useEffect, useState, type ReactNode } from 'react'
|
||||
import { api, ApiError, setCsrf } from '@shared/api/client'
|
||||
import { isRemote, setToken } from '@shared/api/source'
|
||||
import type { LoginResponse, MeDto } from '@shared/api/types'
|
||||
|
||||
interface Auth {
|
||||
me: MeDto | null
|
||||
ready: boolean
|
||||
login: (username: string, password: string) => Promise<void>
|
||||
/** 连别的后端时用 API 令牌登录(不用 Cookie)。 */
|
||||
loginWithToken: (token: string) => Promise<void>
|
||||
logout: () => Promise<void>
|
||||
}
|
||||
|
||||
const AuthContext = createContext<Auth | null>(null)
|
||||
|
||||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
const [me, setMe] = useState<MeDto | null>(null)
|
||||
const [ready, setReady] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
api
|
||||
.get<MeDto>('/api/admin/auth/me')
|
||||
.then((m) => {
|
||||
setCsrf(m.csrf_token ?? null)
|
||||
setMe(m)
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
if (!(e instanceof ApiError) || (e.status !== 401 && e.status !== 403)) console.error(e)
|
||||
})
|
||||
.finally(() => setReady(true))
|
||||
}, [])
|
||||
|
||||
const login = useCallback(async (username: string, password: string) => {
|
||||
const r = await api.post<LoginResponse>('/api/admin/auth/login', { username, password })
|
||||
setCsrf(r.csrf_token)
|
||||
setMe({ kind: 'user', scope: 'admin', user_id: r.user_id, username: r.username, csrf_token: r.csrf_token })
|
||||
}, [])
|
||||
|
||||
const loginWithToken = useCallback(async (token: string) => {
|
||||
setToken(token)
|
||||
try {
|
||||
const m = await api.get<MeDto>('/api/admin/auth/me')
|
||||
setCsrf(m.csrf_token ?? null)
|
||||
setMe(m)
|
||||
} catch (e) {
|
||||
setToken('')
|
||||
throw e
|
||||
}
|
||||
}, [])
|
||||
|
||||
const logout = useCallback(async () => {
|
||||
try {
|
||||
if (isRemote()) setToken('')
|
||||
else await api.post('/api/admin/auth/logout')
|
||||
} finally {
|
||||
setCsrf(null)
|
||||
setMe(null)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <AuthContext.Provider value={{ me, ready, login, loginWithToken, logout }}>{children}</AuthContext.Provider>
|
||||
}
|
||||
|
||||
export function useAuth(): Auth {
|
||||
const value = useContext(AuthContext)
|
||||
if (!value) throw new Error('AuthProvider is missing')
|
||||
return value
|
||||
}
|
||||
Reference in new issue
Block a user