최초커밋
This commit is contained in:
119
frontend/components/auth/AuthGuard.tsx
Normal file
119
frontend/components/auth/AuthGuard.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, ReactNode } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
import { LoadingSpinner } from "@/components/common/LoadingSpinner";
|
||||
|
||||
interface AuthGuardProps {
|
||||
children: ReactNode;
|
||||
requireAuth?: boolean;
|
||||
requireAdmin?: boolean;
|
||||
redirectTo?: string;
|
||||
fallback?: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증 보호 컴포넌트
|
||||
* 로그인 상태 및 권한에 따라 접근을 제어
|
||||
*/
|
||||
export function AuthGuard({
|
||||
children,
|
||||
requireAuth = true,
|
||||
requireAdmin = false,
|
||||
redirectTo = "/login",
|
||||
fallback,
|
||||
}: AuthGuardProps) {
|
||||
const { isLoggedIn, isAdmin, loading, error } = useAuth();
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) return;
|
||||
|
||||
// 인증이 필요한데 로그인되지 않은 경우
|
||||
if (requireAuth && !isLoggedIn) {
|
||||
router.push(redirectTo);
|
||||
return;
|
||||
}
|
||||
|
||||
// 관리자 권한이 필요한데 관리자가 아닌 경우
|
||||
if (requireAdmin && !isAdmin) {
|
||||
router.push("/dashboard"); // 또는 권한 없음 페이지
|
||||
return;
|
||||
}
|
||||
}, [isLoggedIn, isAdmin, loading, requireAuth, requireAdmin, redirectTo, router]);
|
||||
|
||||
// 로딩 중
|
||||
if (loading) {
|
||||
return (
|
||||
fallback || (
|
||||
<div className="flex min-h-screen items-center justify-center">
|
||||
<LoadingSpinner size="lg" text="인증 정보를 확인하고 있습니다..." />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// 에러 발생
|
||||
if (error && requireAuth) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="mb-2 text-red-500">⚠️</div>
|
||||
<p className="mb-4 text-gray-600">{error}</p>
|
||||
<button
|
||||
onClick={() => router.push("/login")}
|
||||
className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
|
||||
>
|
||||
로그인 페이지로 이동
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 인증 조건을 만족하지 않는 경우
|
||||
if (requireAuth && !isLoggedIn) {
|
||||
return fallback || null;
|
||||
}
|
||||
|
||||
if (requireAdmin && !isAdmin) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="mb-2 text-yellow-500">🔒</div>
|
||||
<p className="mb-4 text-gray-600">관리자 권한이 필요합니다.</p>
|
||||
<button
|
||||
onClick={() => router.push("/dashboard")}
|
||||
className="rounded bg-gray-500 px-4 py-2 text-white hover:bg-gray-600"
|
||||
>
|
||||
메인으로 돌아가기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 모든 조건을 만족하는 경우 자식 컴포넌트 렌더링
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그인 여부만 확인하는 간단한 가드
|
||||
*/
|
||||
export function RequireAuth({ children }: { children: ReactNode }) {
|
||||
return <AuthGuard requireAuth={true}>{children}</AuthGuard>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 권한을 요구하는 가드
|
||||
*/
|
||||
export function RequireAdmin({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<AuthGuard requireAuth={true} requireAdmin={true}>
|
||||
{children}
|
||||
</AuthGuard>
|
||||
);
|
||||
}
|
||||
|
||||
export default AuthGuard;
|
||||
Reference in New Issue
Block a user