В современных веб-приложениях управление сессиями пользователей является критически важным аспектом безопасности и пользовательского опыта. React Router предоставляет гибкие инструменты для перенаправления пользователей и контроля доступа к различным маршрутам, что особенно актуально при работе с истекшими сессиями.
Для обработки истекших сессий используется концепция защищённых маршрутов. Создаётся компонент-обёртка, который проверяет состояние аутентификации пользователя перед отображением целевого компонента.
Пример защищённого маршрута:
import { Navigate } from 'react-router-dom';
function ProtectedRoute({ isAuthenticated, children }) {
if (!isAuthenticated) {
return ;
}
return children;
}
Ключевые моменты:
isAuthenticated — логическое состояние аутентификации,
которое можно получать из контекста, Redux или хранилища состояния.Navigate используется для программного перенаправления
без перезагрузки страницы.replace предотвращает сохранение текущего URL в истории
браузера, что исключает возможность возвращения на защищённую страницу
после выхода.Для корректной работы защищённых маршрутов необходимо отслеживать состояние сессии. Наиболее распространённые подходы:
JWT в локальном хранилище
(localStorage/sessionStorage) При получении токена от сервера
его сохраняют в localStorage. Проверка актуальности
выполняется перед рендером маршрута:
const token = localStorage.getItem('token');
const isAuthenticated = token !== null && !isTokenExpired(token);
Функция isTokenExpired проверяет дату истечения срока
действия токена.
Контекст состояния (React Context) Более реактивный метод, который позволяет компонентам подписываться на изменения состояния аутентификации:
import { createContext, useContext, useState } from 'react';
const AuthContext = createContext();
export function AuthProvider({ children }) {
const [isAuthenticated, setIsAuthenticated] = useState(false);
return (
{children}
);
}
export function useAuth() {
return useContext(AuthContext);
}
Это позволяет обновлять состояние сессии в режиме реального времени и автоматически перенаправлять пользователя на страницу входа при истечении токена.
React Router 6 предоставляет компонент ,
который используется для управления переходами. Для динамического
контроля состояния сессии рекомендуется использовать эффект
React:
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
function SessionChecker({ isAuthenticated }) {
const navigate = useNavigate();
useEffect(() => {
if (!isAuthenticated) {
navigate('/login', { replace: true });
}
}, [isAuthenticated, navigate]);
return null;
}
Преимущество такого подхода:
Даже при наличии защищённых маршрутов, пользователь может оставаться на странице до истечения сессии. Для обработки истёкшей сессии на уровне API-запросов рекомендуется:
async function fetchWithAuth(url, options = {}) {
const token = localStorage.getItem('token');
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Bearer ${token}`,
...options.headers
}
});
if (response.status === 401) {
localStorage.removeItem('token');
window.location.href = '/login';
return;
}
return response.json();
}
Такой подход обеспечивает согласованность между состоянием сессии на клиенте и сервере.
Для улучшения пользовательского опыта полезно сохранять URL, на который пользователь пытался попасть до выхода, чтобы после повторной аутентификации он автоматически возвращался на нужную страницу.
import { Navigate, useLocation } from 'react-router-dom';
function ProtectedRoute({ isAuthenticated, children }) {
const location = useLocation();
if (!isAuthenticated) {
return ;
}
return children;
}
После успешного входа можно прочитать state.from и
перенаправить пользователя обратно:
import { useLocation, useNavigate } from 'react-router-dom';
function Login() {
const location = useLocation();
const navigate = useNavigate();
const from = location.state?.from?.pathname || '/';
function handleLogin() {
// логика аутентификации
navigate(from, { replace: true });
}
}
Для автоматического выхода при бездействии можно использовать таймеры на клиенте, который по истечении определённого периода неактивности сбрасывает токен и выполняет редирект.
Пример реализации с хуком useEffect:
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
function useAutoLogout(timeout = 15 * 60 * 1000) {
const navigate = useNavigate();
useEffect(() => {
let timer = setTimeout(() => {
localStorage.removeItem('token');
navigate('/login', { replace: true });
}, timeout);
const resetTimer = () => {
clearTimeout(timer);
timer = setTimeout(() => {
localStorage.removeItem('token');
navigate('/login', { replace: true });
}, timeout);
};
window.addEventListener('mousemove', resetTimer);
window.addEventListener('keydown', resetTimer);
return () => {
clearTimeout(timer);
window.removeEventListener('mousemove', resetTimer);
window.removeEventListener('keydown', resetTimer);
};
}, [navigate, timeout]);
}
Такой подход обеспечивает комплексное управление истёкшими сессиями и предотвращает доступ к защищённым ресурсам после длительного бездействия.
В React Router обработка истёкших сессий строится на комбинации защищённых маршрутов, программных редиректов и контроля состояния аутентификации. Использование контекста, проверок на уровне API и сохранения исходного URL позволяет реализовать безопасное и удобное для пользователя управление сессиями.