第一次提交
This commit is contained in:
100
app-instance/frontend/components/AuthGuard.tsx
Normal file
100
app-instance/frontend/components/AuthGuard.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
||||
import { buildAuthPortalUrl } from '@/lib/auth-portal';
|
||||
import { clearTokens, getMe, isLoggedIn } from '@/lib/api';
|
||||
import { useChatStore } from '@/lib/store';
|
||||
|
||||
export default function AuthGuard({
|
||||
children,
|
||||
minHeightClassName = 'min-h-[calc(100vh-3.5rem)]',
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
minHeightClassName?: string;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const searchParams = useSearchParams();
|
||||
const user = useChatStore((s) => s.user);
|
||||
const setUser = useChatStore((s) => s.setUser);
|
||||
const setIsAuthLoading = useChatStore((s) => s.setIsAuthLoading);
|
||||
const isAuthLoading = useChatStore((s) => s.isAuthLoading);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
const init = async () => {
|
||||
if (!isLoggedIn()) {
|
||||
setUser(null);
|
||||
if (!cancelled) {
|
||||
setIsAuthLoading(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (useChatStore.getState().user) {
|
||||
if (!cancelled) {
|
||||
setIsAuthLoading(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setIsAuthLoading(true);
|
||||
try {
|
||||
const me = await getMe();
|
||||
if (cancelled) return;
|
||||
setUser(me);
|
||||
} catch {
|
||||
clearTokens();
|
||||
if (cancelled) return;
|
||||
setUser(null);
|
||||
} finally {
|
||||
if (!cancelled) {
|
||||
setIsAuthLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [setIsAuthLoading, setUser]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isPublicRoute = pathname === '/login' || pathname === '/register';
|
||||
const loggedIn = isLoggedIn();
|
||||
|
||||
if (!loggedIn && !isPublicRoute) {
|
||||
const search = searchParams?.toString();
|
||||
const nextPath = search ? `${pathname}?${search}` : pathname;
|
||||
window.location.replace(buildAuthPortalUrl('/login', nextPath));
|
||||
return;
|
||||
}
|
||||
|
||||
if (loggedIn && user && isPublicRoute) {
|
||||
router.replace('/');
|
||||
}
|
||||
}, [isAuthLoading, pathname, router, searchParams, user]);
|
||||
|
||||
if (isAuthLoading) {
|
||||
return (
|
||||
<div className={`flex ${minHeightClassName} items-center justify-center`}>
|
||||
<div className="text-muted-foreground">加载中...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const isPublicRoute = pathname === '/login' || pathname === '/register';
|
||||
if (!isPublicRoute && (!isLoggedIn() || !user)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
}
|
||||
Reference in New Issue
Block a user