Список управления доступом (ACL)

ACL (список управления доступом) используется для управления разрешениями на работу с ресурсом. Вы можете предоставить разрешения ролям или пропустить ограничения ролей и напрямую ограничить разрешения. Система ACL предоставляет гибкий механизм управления разрешениями, поддерживая фрагменты разрешений, промежуточное программное обеспечение, условное решение и другие методы.

Примечание

Объекты ACL принадлежат источникам данных (dataSource.acl). Доступ к ACL основного источника данных можно получить через app.acl. Информацию об использовании ACL других источников данных см. в разделе Управление источниками данных.

Регистрация сниппетов разрешений

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

acl.registerSnippet({
  name: 'ui.customRequests', // Префикс ui.* указывает на разрешения, которые можно настраивать в интерфейсе
  actions: ['customRequests:*'], // Соответствующие операции ресурса, поддерживаются подстановочные знаки
});

Разрешения, пропускающие ролевые ограничения (allow)

acl.allow() используется, чтобы позволить определенным операциям обходить ограничения роли, подходит для общедоступных API, сценариев, требующих динамической оценки разрешений, или случаев, когда решение о разрешении должно основываться на контексте запроса.

// Публичный доступ, вход не требуется
acl.allow('app', 'getLang', 'public');

// Доступно для вошедших в систему пользователей
acl.allow('app', 'getInfo', 'loggedIn');

// На основе пользовательского условия
acl.allow('orders', ['create', 'update'], (ctx) => {
  return ctx.auth.user?.isAdmin ?? false;
});

описание параметра условия:

  • 'public': любой пользователь (включая неаутентифицированных пользователей) может получить доступ без какой-либо аутентификации.
  • 'loggedIn': доступ могут получить только вошедшие в систему пользователи, требуется действительный идентификатор пользователя.
  • (ctx) => Promise<boolean> или (ctx) => boolean: пользовательская функция, которая динамически определяет, разрешен ли доступ на основе контекста запроса, может реализовывать сложную логику разрешений.

Регистрация промежуточного ПО разрешений (use)

acl.use() используется для регистрации специального промежуточного ПО разрешений, позволяя вставлять пользовательскую логику в поток проверки. Обычно используется вместе с ctx.permission для собственных правил доступа. Подходит для сценариев, требующих нетипичного контроля разрешений, например: публичные формы с отдельной проверкой пароля, динамические проверки на основе параметров запроса и т. д.

Типичные сценарии применения:

  • Сценарии общедоступной формы: нет пользователя, нет роли, но разрешения должны быть ограничены с помощью специальных паролей.
  • Контроль разрешений на основе параметров запроса, IP-адресов и других условий.
  • Пользовательские правила разрешений, пропуск или изменение процесса проверки разрешений по умолчанию.

Управление разрешениями через ctx.permission:

acl.use(async (ctx, next) => {
  const { resourceName, actionName } = ctx.action;

  // Пример: публичной форме требуется проверка пароля, чтобы пропустить проверку разрешений
  if (resourceName === 'publicForms' && actionName === 'submit') {
    const password = ctx.request.body?.password;
    if (password === 'your-secret-password') {
      // Проверка пройдена, пропускаем проверку разрешений
      ctx.permission = {
        skip: true,
      };
    } else {
      ctx.throw(403, 'Неверный пароль');
    }
  }

  // Выполнить проверку разрешений (продолжить поток ACL)
  await next();
});

Описание свойства ctx.permission:

  • skip: true: пропустить последующие проверки разрешений ACL и напрямую разрешить доступ.
  • Может быть динамически настроен в промежуточном программном обеспечении на основе пользовательской логики для достижения гибкого контроля разрешений.

Добавление фиксированных ограничений данных для определенных операций (addFixedParams)

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

acl.addFixedParams('roles', 'destroy', () => {
  return {
    filter: {
      $and: [
        { 'name.$ne': 'root' },
        { 'name.$ne': 'admin' },
        { 'name.$ne': 'member' },
      ],
    },
  };
});

// Даже если у пользователя есть разрешение на удаление ролей, он не может удалить системные роли, такие как root, admin и member

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

Проверка разрешений (can)

acl.can() используется для проверки наличия у роли разрешения на выполнение указанной операции, возвращая объект результата разрешения или null. Обычно используется для динамической проверки разрешений в бизнес-логике, например для определения того, разрешены ли определенные операции на основе ролей в промежуточном программном обеспечении или обработчиках операций.

const result = acl.can({
  roles: ['admin', 'manager'], // Можно передать одну роль или массив ролей
  resource: 'orders',
  action: 'delete',
});

if (result) {
  console.log(`Role ${result.role} can execute ${result.action} operation`);
  // result.params содержит фиксированные параметры, заданные через addFixedParams
  console.log('Fixed parameters:', result.params);
} else {
  console.log('No permission to execute this operation');
}

Совет. Если передано несколько ролей, каждая роль будет проверена последовательно, и будет возвращен результат для первой роли, имеющей разрешение.

Определения типов:

interface CanArgs {
  role?: string;      // Одна роль
  roles?: string[];   // Несколько ролей (проверяются последовательно, возвращается первая роль с разрешением)
  resource: string;   // Имя ресурса
  action: string;     // Имя операции
}

interface CanResult {
  role: string;       // Роль с разрешением
  resource: string;   // Имя ресурса
  action: string;     // Имя операции
  params?: any;       // Информация о фиксированных параметрах (если задано через addFixedParams)
}

Регистрация настраиваемых операций (setAvailableAction)

Если вы хотите, чтобы в интерфейсе можно было настраивать пользовательские операции (например, отображение на странице управления ролями), вам необходимо использовать setAvailableAction для их регистрации. Зарегистрированные операции появятся в интерфейсе настройки разрешений, где администраторы смогут настраивать разрешения на операции для различных ролей.

acl.setAvailableAction('importXlsx', {
  displayName: '{{t("Import")}}', // Имя, отображаемое в интерфейсе; поддерживается интернационализация
  type: 'new-data',               // Тип операции
  onNewRecord: true,              // Применяется ли при создании новых записей
});

Описание параметра:

  • displayName: имя, отображаемое в интерфейсе настройки разрешений, поддерживает интернационализацию (с использованием формата {{t("key")}}).
  • type: тип операции, определяет классификацию этой операции в конфигурации разрешений.
    • 'new-data': операции по созданию новых данных (например, импорт, создание и т. д.).
    • 'existing-data': операции, изменяющие существующие данные (например, обновление, удаление и т. д.).
  • onNewRecord: вступает ли в силу при создании новых записей, действует только для типа 'new-data'.

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