Почему не работает ограничение RLS в 1С и как устроена логика объединения прав доступа?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При настройке прав доступа в системе «1С:Предприятие» разработчики часто сталкиваются с ситуацией, когда вновь созданная роль с ограничением на уровне записей (RLS) попросту не срабатывает. Например, мы хотим скрыть от пользователя определенный счет (скажем, счет "50.01"), прописываем условие в ограничении чтения, но пользователь все равно продолжает видеть этот объект в списке. В этой статье мы подробно разберем, почему так происходит, как платформа обрабатывает пересекающиеся роли и какие альтернативные (и более производительные) способы существуют для решения этой задачи.

1. Почему не сработало ограничение: логика объединения ролей по «ИЛИ»

Для того чтобы понять причину «неработающего» RLS, нам необходимо детально изучить базовый архитектурный принцип работы системы прав доступа в «1С:Предприятие». В платформе права доступа являются аддитивными (складывающимися). Это означает следующее:

  1. Принцип объединения: Если пользователю назначено несколько ролей, и хотя бы одна из них разрешает чтение или изменение объекта без ограничений (или с более мягким ограничением), то доступ к данным будет предоставлен в максимально возможном объеме.
  2. Логика «ИЛИ»: Платформа проверяет ограничения RLS для каждой роли абсолютно независимо друг от друга. Результаты этих проверок затем объединяются логическим оператором «ИЛИ». Если в роли ПолныеПрава или любой другой типовой роли у пользователя разрешено чтение плана счетов без ограничений, а в нашей кастомной роли ОграничениеДоступа написано Хозрасчетный ГДЕ НЕ Хозрасчетный.Код = "50.01", итоговый запрос к базе данных будет вычислять условие: Истина ИЛИ (Код <> "50.01"). Результат этого выражения всегда равен Истина, и ограничение игнорируется.
  3. Отсутствие запрещающих ролей: В метаданных 1С не существует понятия «запрещающей роли», которая обладала бы более высоким приоритетом и могла бы перекрыть разрешения, выданные другими ролями. Нельзя создать «минусовую» роль, которая бы гарантированно отнимала права.

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

2. Как решить задачу «одним махом» без изменения всех ролей

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

Вариант А. Программное ограничение через расширение конфигурации

Если ваша задача заключается в том, чтобы просто скрыть определенные элементы (например, счета, склады или контрагентов) от глаз пользователя в интерфейсе, мы можем отказаться от тяжелого механизма RLS на уровне СУБД и внедрить фильтрацию программно через механизм расширений.

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

  1. Создаем расширение конфигурации.
  2. Добавляем в расширение форму списка нужного объекта (например, форму списка плана счетов).
  3. Создаем обработчик ПриСозданииНаСервере с методом &После или &Вместо.
  4. Прописываем установку отбора в динамический список.

Рассмотрим пример кода, который исключает счет "50.01" из динамического списка формы:


&После("ПриСозданииНаСервере")
Процедура Расш_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    // Проверяем, нужно ли применять ограничение для текущего пользователя
    Если РольДоступна("ОграничениеДоступа") Тогда
        
        // Находим или добавляем элемент отбора в динамический список "Список"
        ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
        ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Код");
        ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.НеРавно;
        ЭлементОтбора.ПравоеЗначение = "50.01";
        ЭлементОтбора.Использование = Истина;
        ЭлементОтбора.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
        
    КонецЕсли;
    
КонецПроцедуры

Чтобы пользователь не смог обойти этот отбор, открыв форму самого элемента напрямую (например, по навигационной ссылке), необходимо также программно заблокировать открытие формы элемента:


&После("ПриОткрытии")
Процедура Расш_ПриОткрытииПосле(Отказ)
    
    Если РольДоступна("ОграничениеДоступа") И Объект.Код = "50.01" Тогда
        ПоказатьПредупреждение(, "Доступ к данному счету ограничен администратором системы.");
        Отказ = Истина;
    КонецЕсли;
    
КонецПроцедуры

Этот способ работает быстро, не нагружает СУБД сложными SQL-запросами и легко переносится между релизами конфигурации.

Вариант Б. Использование подписок на события (для запрета изменения данных)

Если ваша цель — не просто скрыть данные, а гарантированно запретить пользователям редактировать или записывать определенные элементы, отличным решением станет использование Подписок на события в расширении.

Разберем, как это сделать:

  1. В расширении создаем новую Подписку на событие.
  2. В качестве источника выбираем нужный объект (например, ПланСчетовОбъект.Хозрасчетный).
  3. В качестве события выбираем ПередЗаписью.
  4. В обработчике подписки пишем проверку роли и блокируем запись транзакции в случае нарушения правил.

Посмотрим на пример реализации обработчика подписки:


Процедура Расш_ПередЗаписьюПланаСчетовПередЗаписью(Источник, Отказ, РежимЗаписи) Экспорт
    
    // Если у пользователя есть ограничивающая роль, запрещаем запись конкретного счета
    Если РольДоступна("ОграничениеДоступа") И Источник.Код = "50.01" Тогда
        ВызватьИсключение "У вас нет прав на создание, изменение или удаление счета 50.01!";
    КонецЕсли;
    
КонецПроцедуры

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

Вариант В. Настройка ограничений через механизмы БСП

Если вы работаете в типовой конфигурации (например, 1С:Бухгалтерия, 1С:ERP или 1С:Управление торговлей), то в них уже интегрирована Библиотека стандартных подсистем (БСП). В БСП встроен мощный и гибкий механизм управления доступом на уровне записей.

Выясним особенности настройки RLS через БСП:

3. Производительность RLS и важные подводные камни

Прежде чем принять окончательное решение о повсеместном внедрении ограничений на уровне записей (RLS), проанализируем возможные негативные последствия для производительности вашей информационной базы:

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

← На главную