Защищенные маршруты и авторизация

Inferno использует Inferno Router для организации маршрутов в одностраничных приложениях. В основе лежит компонент <Router>, который оборачивает дерево приложения и управляет отображением компонентов в зависимости от текущего URL. Для определения маршрутов применяется компонент <Route>, а для переходов — <Link>.

Пример базовой структуры маршрутов:

import { render } from 'inferno';
import { Router, Route, Link } from 'inferno-router';
import Home from './Home';
import Dashboard from './Dashboard';

const App = () => (
  <Router>
    <nav>
      <Link to="/">Главная</Link>
      <Link to="/dashboard">Панель</Link>
    </nav>
    <Route path="/" component={Home} />
    <Route path="/dashboard" component={Dashboard} />
  </Router>
);

render(<App />, document.getElementById('root'));

В этом примере <Route> связывает URL с компонентом, а <Link> позволяет навигацию без перезагрузки страницы.


Механизм защиты маршрутов

Для реализации защищенных маршрутов необходимо использовать условную отрисовку компонентов на основе состояния авторизации. Основная идея заключается в том, чтобы проверять, авторизован ли пользователь, и в зависимости от этого либо отображать запрошенный компонент, либо перенаправлять на страницу логина.

Создание HOC для защищенного маршрута

Используется паттерн Higher-Order Component (HOC) для обертки маршрута:

import { Route, Redirect } from 'inferno-router';

const ProtectedRoute = ({ component: Component, isAuthenticated, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      isAuthenticated ? <Component {...props} /> : <Redirect to="/login" />
    }
  />
);

Здесь ProtectedRoute проверяет проп isAuthenticated. Если пользователь не авторизован, выполняется перенаправление на /login.


Управление состоянием авторизации

Состояние авторизации можно хранить в глобальном store или в локальном состоянии приложения через Inferno.Component или useState/useEffect (при использовании Inferno Hooks).

Пример с использованием глобального состояния через контекст:

import { createContext } from 'inferno';
import { useContext } from 'inferno-hooks';

const AuthContext = createContext();

const AuthProvider = ({ children }) => {
  const [isAuthenticated, setAuthenticated] = useState(false);

  const login = () => setAuthenticated(true);
  const logout = () => setAuthenticated(false);

  return (
    <AuthContext.Provider value={{ isAuthenticated, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

const useAuth = () => useContext(AuthContext);

Компонент AuthProvider оборачивает приложение, предоставляя доступ к состоянию авторизации любому компоненту через хук useAuth.


Интеграция защищенного маршрута

Комбинация HOC и контекста позволяет строить защищенные маршруты:

const Dashboard = () => <div>Панель пользователя</div>;
const Login = () => <div>Форма входа</div>;

const App = () => {
  const { isAuthenticated } = useAuth();

  return (
    <Router>
      <Route path="/login" component={Login} />
      <ProtectedRoute path="/dashboard" component={Dashboard} isAuthenticated={isAuthenticated} />
    </Router>
  );
};

В этом примере доступ к /dashboard возможен только при isAuthenticated = true.


Перенаправления и хранение предыдущего маршрута

Для улучшения UX рекомендуется хранить предыдущий URL, на который пытался зайти пользователь. После успешного логина можно автоматически перенаправлять его обратно.

const ProtectedRoute = ({ component: Component, isAuthenticated, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      isAuthenticated ? (
        <Component {...props} />
      ) : (
        <Redirect to={{ pathname: "/login", state: { from: props.location } }} />
      )
    }
  />
);

В компоненте Login можно получить props.location.state.from и после успешного входа выполнить history.push(from).


Контроль доступа на уровне компонентов

Иногда необходимо не только блокировать целые маршруты, но и контролировать доступ к отдельным элементам внутри страницы. Для этого используется проверка прав пользователя и условная отрисовка:

const AdminPanel = ({ user }) => (
  <>
    {user.role === 'admin' ? (
      <div>Административная панель</div>
    ) : (
      <div>Доступ ограничен</div>
    )}
  </>
);

Такой подход позволяет гибко управлять доступом без изменения структуры маршрутов.


Практические рекомендации

  • Минимизация лишних перерендеров: оборачивать защищенные маршруты и контекст в мемоизированные компоненты (Inferno.memo), чтобы не создавать лишние обновления.
  • Использование lazy loading: для компонентов, доступ к которым ограничен, использовать динамический импорт, чтобы код загружался только при авторизованном доступе.
  • Централизация авторизации: хранение состояния в контексте или глобальном store позволяет легко расширять приложение и добавлять новые защищенные маршруты без дублирования логики.

Эта структура позволяет создавать безопасные и управляемые маршруты в приложениях Inferno, обеспечивая как проверку авторизации, так и удобное управление навигацией и состоянием пользователя.