47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import { Navigate, useLocation } from 'react-router-dom'
|
|
import { useQuery } from '@tanstack/react-query'
|
|
import { Loader2 } from 'lucide-react'
|
|
import { api } from '@/lib/api'
|
|
|
|
function getStoredToken(): string | null {
|
|
try { return localStorage.getItem('access_token') } catch { return null }
|
|
}
|
|
|
|
export function AccessGuard({ children, requireAdmin = false }: { children: React.ReactNode; requireAdmin?: boolean }) {
|
|
const location = useLocation()
|
|
const token = getStoredToken()
|
|
|
|
const { data: status, isLoading } = useQuery({
|
|
queryKey: ['access-auth-status', token],
|
|
queryFn: () => api.accessAuthStatus(),
|
|
// 即使 token 为空也查询一次,用于确认服务端是否启用了门控
|
|
enabled: true,
|
|
staleTime: 5 * 60 * 1000,
|
|
})
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="h-screen w-full flex items-center justify-center bg-base text-foreground">
|
|
<Loader2 className="h-6 w-6 animate-spin text-accent" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
// 未启用门控,直接放行
|
|
if (!status?.enabled) {
|
|
return <>{children}</>
|
|
}
|
|
|
|
// 未验证,跳转到登录页
|
|
if (!status.verified) {
|
|
return <Navigate to="/verify" state={{ from: location.pathname }} replace />
|
|
}
|
|
|
|
// 需要管理员权限但当前非管理员
|
|
if (requireAdmin && status.role !== 'admin') {
|
|
return <Navigate to="/" replace />
|
|
}
|
|
|
|
return <>{children}</>
|
|
}
|