本文介绍如何在 react router v6 中通过自定义路由守卫组件,统一实现“已登录用户禁止访问登录/注册页”和“未登录用户禁止访问私有页面”的双向权限控制,避免重复逻辑、提升可维护性。
在现代 React 应用中,仅靠单向的 PrivateRoute(即“未登录则跳转登录页”)不足以满足完整的权限流需求。真实场景中,我们同样需要防止已登录用户意外或恶意返回 /login、/register、/forgotpassword 等身份初始化页面——这不仅影响用户体验,还可能引发状态冲突(如重复登录、覆盖本地缓存等)。
最佳实践是遵循 关注点分离(Separation of Concerns) 原则,为两类场景分别设计语义清晰的守卫组件:
// guards.tsx
import { Navigate, Outlet } from 'react-router-dom';
export function PrivateRoute() {
const user = JSON.parse(localStorage.getItem('user') || 'null');
return user ? : ;
}
export function AnonymousRoute() {
const user = JSON.parse(localStorage.getItem('user') || 'null');
return user ? : ;
}配合 React Router v6 的嵌套路由结构,配置更简洁、语义更明确:
// App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { PrivateRoute, AnonymousRoute } from './guards';
import MenuBar from './components/MenuBar';
import Dashboard from './pages/Dashboard';
import Profile from './pages/Profile';
import LoginUser from './pages/LoginUser';
import RegisterUser from './pages/RegisterUser';
import ForgotPassword from './pages/ForgotPassword';
function App() {
return (
{/* 已登录才可访问的页面 */}
}>
} />
} />
{/* 仅未登录用户可访问的页面 */}
} />
} />
} />
{/* 可选:404 路由应放在最后 */}
);
}
export default App;若因历史原因必须复用单一组件,可扩展为带条件参数的 ProtectedRoute:
interface ProtectedRouteProps {
isAuth?: boolean; // true → 私有路由;false 或 undefined → 匿名路由
target: string; // 重定向目标路径
}
export function ProtectedRoute({ isAuth = true, target }: ProtectedRouteProps) {
const user = JSON.parse(localStorage.getItem('user') || 'null');
if (isAuth) {
return user ? : ;
}
return user ? : ;
}使用方式:
}>... }>...
但该设计违反单一职责原则,可读性与可测试性下降,仅建议临时过渡使用。
通过以上设计,你既能复用核心鉴权逻辑,又能保持路由配置的高内聚与低耦合,为后续接入 OAuth、角色权限(RBAC)或动态路由打下坚实基础。