Редиректы для неавторизованных пользователей

В React Router управление доступом к маршрутам осуществляется через редиректы, которые перенаправляют пользователя на страницы входа или регистрации, если он не прошёл аутентификацию. Для этого используются компоненты и функции защиты маршрутов, известные как Protected Routes.


Protected Route: базовая реализация

Для контроля доступа создаётся компонент-обёртка, который проверяет состояние авторизации. Например, состояние авторизации может храниться в контексте (AuthContext) или глобальном состоянии (Redux):

import { Navigate } from "react-router-dom";

function ProtectedRoute({ isAuthenticated, children }) {
    if (!isAuthenticated) {
        return ;
    }
    return children;
}
  • isAuthenticated — булевый флаг, указывающий, авторизован пользователь или нет.
  • children — элементы, доступные только для авторизованных пользователей.
  • replace — предотвращает добавление лишней записи в историю браузера при редиректе.

Использование Protected Route

В маршрутах приложения защищённые страницы оборачиваются в компонент ProtectedRoute:

import { Routes, Route } from "react-router-dom";

function App({ isAuthenticated }) {
    return (
        
            } />
            
                        
                    
                }
            />
        
    );
}

Таким образом, при попытке перехода на /dashboard без авторизации пользователь автоматически попадёт на /login.


Редирект с сохранением предыдущего пути

Часто требуется возвращать пользователя на страницу, на которую он пытался попасть до редиректа. Для этого используется объект state:

import { Navigate, useLocation } from "react-router-dom";

function ProtectedRoute({ isAuthenticated, children }) {
    const location = useLocation();

    if (!isAuthenticated) {
        return ;
    }

    return children;
}

В компоненте входа можно считать исходный путь:

import { useLocation, useNavigate } from "react-router-dom";

function LoginPage() {
    const navigate = useNavigate();
    const location = useLocation();
    const from = location.state?.from?.pathname || "/";

    const handleLogin = () => {
        // логика аутентификации
        navigate(from, { replace: true });
    };

    return ;
}
  • location.state?.from?.pathname — путь, с которого произошёл редирект.
  • navigate(from, { replace: true }) — после успешного входа пользователь возвращается на исходную страницу.

Комбинация с ролями

Если требуется различать доступ по ролям, ProtectedRoute расширяется проверкой:

function ProtectedRoute({ isAuthenticated, userRole, requiredRole, children }) {
    if (!isAuthenticated) {
        return ;
    }
    if (requiredRole && userRole !== requiredRole) {
        return ;
    }
    return children;
}
  • userRole — роль текущего пользователя.
  • requiredRole — роль, необходимая для доступа.
  • unauthorized — страница, которая отображается при отсутствии прав.

Lazy-loading защищённых маршрутов

React Router поддерживает ленивую загрузку компонентов. Это позволяет оптимизировать производительность приложения:

import { lazy, Suspense } from "react";

const Dashboard = lazy(() => import("./Dashboard"));


            Загрузка...
}> } />
  • Suspense отображает fallback-контент до завершения загрузки компонента.
  • Поддержка ленивой загрузки защищённых маршрутов не требует изменения логики редиректов.

Масштабирование приложения

Для крупных проектов рекомендуется использовать структуру маршрутов через массив конфигураций:

const routes = [
    { path: "/login", element:  },
    {
        path: "/dashboard",
        element: ,
        protected: true
    },
    {
        path: "/admin",
        element: ,
        protected: true,
        role: "admin"
    }
];

Рендер маршрутов через map с применением ProtectedRoute:


    {routes.map(({ path, element, protected: isProtected, role }, index) => (
        
                        {element}
                    
                ) : (
                    element
                )
            }
        />
    ))}
  • Такой подход упрощает добавление новых защищённых маршрутов и управление доступом.
  • Лёгкая интеграция с контекстом или глобальным хранилищем состояния для проверки авторизации и ролей.

Особенности работы с

  1. replace vs push

    • replace={true} заменяет текущую запись в истории браузера.
    • Без replace редирект добавляет новый шаг в историю, что может вызывать нежелательный эффект «назад» после авторизации.
  2. Использование с динамическими параметрами При редиректе на страницу с параметрами можно передавать их через state или напрямую в to:

  1. Комбинация с query-параметрами Для передачи состояния можно добавлять query-параметры:

Проверка авторизации через хук

Можно создать хук useAuthGuard для повторного использования логики:

import { useLocation, Navigate } from "react-router-dom";
import { useAuth } from "./AuthContext";

export function useAuthGuard(children) {
    const { isAuthenticated } = useAuth();
    const location = useLocation();

    if (!isAuthenticated) {
        return ;
    }

    return children;
}

Это позволяет делать компонент максимально компактным:

)} />