Files
cunkebao_v3/Cunkebao/src/components/ProtectedRoute.tsx

71 lines
2.0 KiB
TypeScript
Raw Normal View History

2025-07-04 15:49:22 +08:00
import React, { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
2025-07-05 16:34:19 +08:00
import { useAuth } from '@/contexts/AuthContext';
2025-07-04 15:49:22 +08:00
// 不需要登录的公共页面路径
const PUBLIC_PATHS = [
'/login',
'/register',
'/forgot-password',
'/reset-password',
'/404',
'/500'
];
interface ProtectedRouteProps {
children: React.ReactNode;
}
export default function ProtectedRoute({ children }: ProtectedRouteProps) {
const { isAuthenticated, isLoading } = useAuth();
const navigate = useNavigate();
const location = useLocation();
// 检查当前路径是否是公共页面
const isPublicPath = PUBLIC_PATHS.some(path =>
location.pathname.startsWith(path)
);
useEffect(() => {
// 如果正在加载,不进行任何跳转
if (isLoading) {
return;
}
// 如果未登录且不是公共页面,重定向到登录页面
if (!isAuthenticated && !isPublicPath) {
// 保存当前URL登录后可以重定向回来
const returnUrl = encodeURIComponent(window.location.href);
navigate(`/login?returnUrl=${returnUrl}`, { replace: true });
return;
}
// 如果已登录且在登录页面,重定向到首页
if (isAuthenticated && location.pathname === '/login') {
navigate('/', { replace: true });
return;
}
}, [isAuthenticated, isLoading, location.pathname, navigate, isPublicPath]);
// 如果正在加载,显示加载状态
if (isLoading) {
return (
<div className="flex h-screen w-screen items-center justify-center">
<div className="text-gray-500">...</div>
</div>
);
}
// 如果未登录且不是公共页面,不渲染内容(等待重定向)
if (!isAuthenticated && !isPublicPath) {
return null;
}
// 如果已登录且在登录页面,不渲染内容(等待重定向)
if (isAuthenticated && location.pathname === '/login') {
return null;
}
// 其他情况正常渲染
return <>{children}</>;
}