Роли и права доступа

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


Определение ролей

Роли в приложении обычно представляются через объект или перечисление, которое описывает набор доступов. Например:

export const Roles = {
  ADMIN: 'admin',
  USER: 'user',
  GUEST: 'guest',
};

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


Защищённые маршруты

TanStack Router предоставляет возможность создавать маршруты с условием доступа. Для этого используется свойство beforeLoad или loader, в которых можно проверять роль пользователя.

Пример защищённого маршрута:

import { createRouter, Route } from '@tanstack/router';
import { Roles } from './roles';
import { getCurrentUser } from './auth';

const protectedRoute = new Route({
  path: '/admin',
  element: ,
  beforeLoad: async () => {
    const user = await getCurrentUser();
    if (!user || user.role !== Roles.ADMIN) {
      throw new Error('Доступ запрещён');
    }
  },
});

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


Динамическая маршрутизация по ролям

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

function getRoutesForRole(role) {
  const baseRoutes = [homeRoute, profileRoute];

  if (role === Roles.ADMIN) {
    return [...baseRoutes, adminRoute, manageUsersRoute];
  }

  if (role === Roles.USER) {
    return [...baseRoutes, dashboardRoute];
  }

  return baseRoutes;
}

const router = createRouter({
  routes: getRoutesForRole(currentUser.role),
});

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


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

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

function AdminButton({ user }) {
  if (user.role !== Roles.ADMIN) return null;

  return ;
}

Это позволяет создавать контекстно-зависимый интерфейс, где элементы управления отображаются только пользователям с нужными правами.


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

Для удобства управления ролями TanStack Router легко интегрируется с глобальными состояниями, такими как Redux, Zustand или Context API. Например:

import { useStore } from './store';

const protectedRoute = new Route({
  path: '/settings',
  element: ,
  beforeLoad: () => {
    const user = useStore.getState().currentUser;
    if (!user || user.role !== Roles.ADMIN) {
      throw new Error('Доступ запрещён');
    }
  },
});

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


Редиректы при отсутствии доступа

Для улучшения UX можно настроить автоматические редиректы для пользователей без прав доступа:

const router = createRouter({
  routes: [
    {
      path: '/admin',
      element: ,
      beforeLoad: async () => {
        const user = await getCurrentUser();
        if (!user || user.role !== Roles.ADMIN) {
          return '/login'; // редирект на страницу входа
        }
      },
    },
  ],
});

В этом случае попытка доступа к закрытому маршруту приведёт к перенаправлению на страницу авторизации или любую другую, указанную в логике.


Резюме ключевых моментов

  • Роли представляются через константы или перечисления для централизованного управления доступом.
  • Проверка доступа осуществляется через beforeLoad или loader маршрутов.
  • Динамическая генерация маршрутов позволяет отображать только те маршруты, которые доступны текущей роли.
  • Внутри компонентов можно скрывать элементы интерфейса в зависимости от роли пользователя.
  • Интеграция с глобальным состоянием обеспечивает быстрый доступ к данным пользователя.
  • Редиректы при отсутствии прав повышают удобство использования приложения и безопасность.