Защита маршрутов через опции route.auth

В библиотеке Iron маршрутизация строится вокруг декларативного описания путей и привязки к ним метаданных, определяющих поведение системы при переходе. Одним из ключевых механизмов ограничения доступа выступает опция route.auth, которая позволяет встроить проверку авторизации непосредственно в конфигурацию маршрута, не вынося её в отдельные слои логики.

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


Базовая структура маршрута с auth

Типичная конфигурация маршрута в Iron выглядит как объект, где помимо пути и обработчика задаются дополнительные параметры:

const routes = [
  {
    path: '/dashboard',
    component: Dashboard,
    auth: true
  }
]

Значение auth: true означает, что маршрут доступен только авторизованным пользователям. Внутри механизма роутера это интерпретируется как проверка состояния сессии или наличия валидного токена.


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

При переходе по маршруту Iron выполняет последовательность шагов:

  1. Поиск совпадения маршрута
  2. Проверка наличия route.auth
  3. Вызов функции-валидатора (если требуется)
  4. Принятие решения о переходе или редиректе

Упрощённо логика может выглядеть так:

function canActivate(route, user) {
  if (!route.auth) return true;
  if (route.auth === true) return user.isAuthenticated;
  return false;
}

Использование функций в route.auth

Более гибкий подход достигается через передачу функции, позволяющей реализовать сложную логику:

{
  path: '/admin',
  component: AdminPanel,
  auth: (user) => user && user.role === 'admin'
}

Функция получает контекст пользователя и возвращает булево значение. Это позволяет внедрять:

  • проверку ролей
  • проверку подписки
  • ограничения по состоянию аккаунта
  • временные блокировки

Асинхронная авторизация

В реальных приложениях проверка доступа часто требует обращения к серверу. Iron поддерживает асинхронные проверки через промисы:

{
  path: '/billing',
  component: Billing,
  auth: async (user) => {
    const res = await api.checkSubscription(user.id);
    return res.active;
  }
}

При такой модели роутер обязан ожидать завершения проверки перед тем, как принять решение о навигации.

Ключевое поведение:

  • маршрут блокируется до завершения промиса
  • при false выполняется редирект
  • при ошибке запроса возможен fallback на страницу ошибки

Роли и массивы разрешений

Часто доступ определяется списком ролей. В этом случае route.auth может быть массивом:

{
  path: '/moderation',
  component: ModerationPanel,
  auth: ['admin', 'moderator']
}

Внутри Iron выполняется проверка принадлежности роли пользователя:

function checkRole(route, user) {
  if (!Array.isArray(route.auth)) return true;
  return route.auth.includes(user.role);
}

Такой подход удобен для RBAC-модели (Role-Based Access Control), где права группируются по уровням доступа.


Комбинированные правила доступа

На практике часто требуется сочетание нескольких условий. Для этого route.auth может быть объектом:

{
  path: '/settings',
  component: Settings,
  auth: {
    roles: ['user', 'admin'],
    verified: true
  }
}

Логика проверки становится составной:

function complexAuth(route, user) {
  const { roles, verified } = route.auth;

  if (roles && !roles.includes(user.role)) return false;
  if (verified && !user.verified) return false;

  return true;
}

Поведение при отказе в доступе

Iron определяет стандартный механизм обработки отказа:

  • редирект на /login, если пользователь не авторизован
  • редирект на /forbidden, если доступ запрещён по роли
  • возможность кастомного обработчика

Пример настройки:

{
  path: '/admin',
  component: AdminPanel,
  auth: {
    roles: ['admin'],
    redirect: '/forbidden'
  }
}

При этом роутер не просто блокирует переход, но и передаёт управление в систему навигации, сохраняя контекст попытки доступа.


Интеграция с глобальным состоянием

Проверка route.auth почти всегда завязана на глобальное состояние приложения. Обычно это:

  • store пользователя
  • JWT-токен
  • session storage
  • cookie-based сессия

Пример связки:

const user = store.getState().user;

router.beforeEach((route) => {
  return canActivate(route, user);
});

Кеширование результатов проверки

При частых переходах важно избегать повторных дорогих проверок. Iron может кешировать результат auth-функции:

  • по идентификатору пользователя
  • по маршруту
  • по TTL (time-to-live)

Это особенно актуально при асинхронных проверках подписки или прав доступа.


Безопасность и ограничения client-side auth

Несмотря на удобство route.auth, важно учитывать, что клиентская проверка не является полноценной защитой. Она выполняет роль UX-ограничения, но не заменяет серверную авторизацию.

Типичная архитектура требует:

  • дублирования проверки на backend
  • обязательной валидации токена на API
  • отказоустойчивой обработки 401/403 ответов

Динамическое изменение правил доступа

Iron поддерживает обновление маршрутов в рантайме. Это позволяет менять route.auth без перезагрузки приложения:

router.updateRoute('/admin', {
  auth: (user) => user.permissions.includes('admin_access')
});

Такой подход применяется в:

  • feature flag системах
  • A/B тестировании доступа
  • временных ограничениях функционала

Вложенные маршруты и наследование auth

При использовании вложенных маршрутов возможно наследование правил:

{
  path: '/admin',
  auth: ['admin'],
  children: [
    {
      path: '/admin/users',
      component: Users
    }
  ]
}

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


Ошибки конфигурации route.auth

Типичные проблемы при работе с доступом:

  • отсутствие проверки для критического маршрута
  • конфликт ролей между родителем и ребёнком
  • асинхронная функция без обработки ошибок
  • утечка логики авторизации в компонент

Корректная архитектура требует централизованной обработки auth, а не распределения проверок по UI-компонентам.


Поведение при изменении состояния пользователя

Если пользователь выходит из системы во время активной сессии, Iron должен реагировать на это:

  • мгновенный пересчёт доступных маршрутов
  • принудительный редирект с защищённых страниц
  • очистка кеша auth-проверок
store.subscribe((state) => {
  if (!state.user) {
    router.invalidateAuthCache();
    router.navigate('/login');
  }
});

Итоговая модель работы route.auth

Механизм route.auth в Iron формирует слой декларативной безопасности маршрутов, который объединяет:

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

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