Route Guards: защита маршрутов
Route Guard — паттерн клиентской защиты маршрутов, при котором перед отображением страницы проверяется условие (авторизация, роль пользователя) и при несоответствии выполняется редирект.
Зачем нужно
В SPA без route guards пользователь может вручную ввести URL /admin или /dashboard и увидеть страницу или её скелет до проверки прав. Route Guards перехватывают переход и перенаправляют на /login или /403 до рендеринга защищённого контента. Важно понимать, что это клиентская защита — реальная авторизация проверяется на сервере при каждом API-запросе.
Где используется
- Защита авторизованных маршрутов (дашборд, профиль, настройки)
- Разграничение по ролям (admin, moderator, user)
- Редирект авторизованных пользователей от
/loginна/dashboard - Защита WIP-страниц флагами фич (feature flags)
PrivateRoute в React Router
import { Navigate, Outlet } from 'react-router-dom';
import { useAuth } from './hooks/useAuth';
// Компонент-guard: проверяет авторизацию перед рендером дочерних маршрутов
function PrivateRoute() {
const { user, isLoading } = useAuth;
if (isLoading) {
// Пока проверяем авторизацию — показываем загрузку, не рендерим контент
return <div>Проверка авторизации...</div>;
}
if (!user) {
// Не авторизован — редирект на login
// state сохраняет путь для возврата после входа
return <Navigate to="/login" state={{ from: location.pathname }} replace />;
}
// Авторизован — рендерим вложенные маршруты
return <Outlet />;
}
// Использование в роутере
function AppRouter() {
return (
<Routes>
{/* Публичные маршруты */}
<Route path="/" element={<Home />} />
<Route path="/login" element={<Login />} />
<Route path="/about" element={<About />} />
{/* Защищённые маршруты — все внутри PrivateRoute */}
<Route element={<PrivateRoute />}>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
</Route>
{/* Защита по роли */}
<Route element={<RoleGuard requiredRole="admin" />}>
<Route path="/admin" element={<AdminPanel />} />
<Route path="/admin/users" element={<AdminUsers />} />
</Route>
</Routes>
);
}
Guard по ролям
function RoleGuard({ requiredRole }) {
const { user } = useAuth;
if (!user) {
return <Navigate to="/login" replace />;
}
if (!user.roles.includes(requiredRole)) {
return <Navigate to="/403" replace />;
}
return <Outlet />;
}
Возврат на страницу после входа
function Login() {
const navigate = useNavigate;
const location = useLocation;
const { login } = useAuth;
const handleLogin = async (credentials) => {
await login(credentials);
// Вернуть на страницу, с которой пришли
const from = location.state?.from || '/dashboard';
navigate(from, { replace: true });
};
return <LoginForm onSubmit={handleLogin} />;
}
Частые ошибки
- Полагаются только на клиентскую защиту — route guards защищают UX, но не данные; API должен проверять токен при каждом запросе независимо от клиента.
- Не показывают loading state — рендерят защищённый контент на миллисекунду до проверки авторизации (мерцание); всегда обрабатывайте
isLoading. - Бесконечный цикл редиректа — если
AuthRouteредиректит на/login, а/loginснова проходит черезAuthRoute.
Связанные темы
- _MOC SPA
- Клиентский роутинг -- как работает
- History API и hash-routing
- Вложенные маршруты
- Загрузка данных и loading states