Создаём AuthGuard для защиты маршрутов
1. Установка и настройка react-router-dom
Если вы ещё не установили библиотеку для маршрутизации, сделайте это:
npm install react-router-dom
Не забудьте, что при работе с TypeScript, вам понадобится типизация для роутера:
npm install @types/react-router-dom --save-dev
Теперь у нас есть все инструменты, чтобы начать создание.
2. Структура приложения
Давайте обновим нашу структуру проекта. Мы будем использовать следующие основные компоненты:
App.tsx: основной файл с маршрутизацией.ProtectedRoute.tsx: наш AuthGuard.AuthService.ts: сервис для работы с JWT (генерация, валидация и т.д.).- Компоненты страниц
LoginPage,Dashboard,Profile.
Ваш каталог может выглядеть так:
src/
├── components/
│ ├── ProtectedRoute.tsx
│ ├── LoginPage.tsx
│ ├── Dashboard.tsx
│ └── Profile.tsx
└── services/
└── AuthService.ts
3. Реализация AuthService
Начнем с сервиса авторизации. Он помогает управлять токенами: извлекать их из localStorage, проверять их валидность и, при необходимости, удалять.
src/services/AuthService.ts:
export default class AuthService {
private static TOKEN_KEY = 'app_token';
// Сохраняем токен в localStorage
static setToken(token: string) {
localStorage.setItem(this.TOKEN_KEY, token);
}
// Получаем токен из localStorage
static getToken(): string | null {
return localStorage.getItem(this.TOKEN_KEY);
}
// Удаляем токен (выход пользователя)
static clearToken() {
localStorage.removeItem(this.TOKEN_KEY);
}
// Проверяем валидность токена
static isTokenValid(): boolean {
const token = this.getToken();
if (!token) return false;
try {
const payload = JSON.parse(atob(token.split('.')[1])); // Декодируем payload JWT
const currentTime = Math.floor(Date.now() / 1000);
return payload.exp > currentTime; // Сравниваем срок действия токена
} catch (error) {
console.error('Invalid token:', error);
return false;
}
}
}
Этот сервис выполняет простую, но важную функцию — он проверяет срок действия токена и управляет его состоянием в localStorage.
4. Реализация ProtectedRoute
Давайте теперь создадим AuthGuard, который будет проверять, залогинен ли пользователь. Если проверка не пройдена, он перенаправит пользователя на страницу входа.
src/components/ProtectedRoute.tsx:
import React from 'react';
import { Navigate } from 'react-router-dom';
import AuthService from '../services/AuthService';
interface ProtectedRouteProps {
children: React.ReactElement; // Дочерний компонент (например, Dashboard)
}
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
const isAuthenticated = AuthService.isTokenValid();
if (!isAuthenticated) {
// Перенаправляем пользователя на страницу входа
return <Navigate to="/login" replace />;
}
// Если пользователь аутентифицирован, отображаем дочерний компонент
return children;
};
export default ProtectedRoute;
Обратите внимание на использование компонента Navigate из react-router-dom для перенаправления.
5. Настройка маршрутов в App.tsx
Теперь мы можем использовать наш AuthGuard для защиты маршрутов. Добавим ProtectedRoute в нашу маршрутизацию.
src/App.tsx:
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import LoginPage from './components/LoginPage';
import Dashboard from './components/Dashboard';
import Profile from './components/Profile';
import ProtectedRoute from './components/ProtectedRoute';
const App: React.FC = () => {
return (
<Router>
<Routes>
<Route path="/login" element={<LoginPage />} />
{/* Защищённый маршрут для Dashboard */}
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
{/* Защищённый маршрут для Profile */}
<Route
path="/profile"
element={
<ProtectedRoute>
<Profile />
</ProtectedRoute>
}
/>
{/* Страница по умолчанию */}
<Route path="*" element={<Navigate to="/login" replace />} />
</Routes>
</Router>
);
};
export default App;
Теперь любой маршрут, обёрнутый в ProtectedRoute, автоматически проверяется на валидность JWT.
6. Типичные проблемы и их решения
Проблема: JWT истёк, пользователь остаётся на странице.
Решение: добавьте проверку токена в компоненте верхнего уровня, например, в App.tsx. Если токен истёк, вызывайте AuthService.clearToken() и перенаправляйте на /login.
Проблема: пользователь видит мигание защищённого маршрута перед редиректом.
Решение: используйте состояние загрузки isLoading в ProtectedRoute, чтобы дождаться проверки токена перед рендерингом.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ