/** * 客户端认证守卫组件 * * 在客户端检查 localStorage 中的 token * 如果未认证且访问的是需要认证的路径,则跳转到登录页 */ import { useEffect } from 'react'; import { useNavigate, useLocation } from '@remix-run/react'; import { isAuthenticated } from '~/utils/auth-storage'; interface ClientAuthGuardProps { isPublicPath: boolean; } export function ClientAuthGuard({ isPublicPath }: ClientAuthGuardProps) { const navigate = useNavigate(); const location = useLocation(); useEffect(() => { console.log('🔍 [Auth Guard] useEffect 触发', { isPublicPath, pathname: location.pathname }); // 如果是公共路径,不需要检查认证 if (isPublicPath) { console.log('✅ [Auth Guard] 公共路径,跳过认证检查'); return; } // 检查客户端是否已认证(localStorage 中有 token) const token = localStorage.getItem('access_token'); const authenticated = isAuthenticated(); console.log('🔍 [Auth Guard] 认证检查', { token: token ? `${token.substring(0, 20)}...` : null, authenticated, pathname: location.pathname }); if (!authenticated) { console.log('🔒 [Auth Guard] 未认证,重定向到登录页'); // 保存当前路径,登录后可以跳转回来 const redirectTo = location.pathname !== '/login' ? location.pathname : '/'; // 跳转到登录页,并传递重定向目标 navigate(`/login?redirect=${encodeURIComponent(redirectTo)}`, { replace: true }); } else { console.log('✅ [Auth Guard] 已认证,允许访问'); } }, [isPublicPath, navigate, location.pathname]); // 这个组件不渲染任何内容 return null; }