Как настроить RLS с условием "ИЛИ" для объекта в расширении 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Исходная задача: в конфигурацию через расширение добавлен документ "НарядЗаказ". В нем есть два реквизита с типом СправочникСсылка.СтруктураПредприятия: Подразделение и ПодразделениеПолучатель. Необходимо предоставить пользователю доступ к документу, если у него есть права на подразделение, указанное в поле Подразделение, ИЛИ на подразделение из поля ПодразделениеПолучатель.

Стандартный алгоритм настройки RLS для нового объекта

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

Шаг 1. Включение объекта в списки с ограничением доступа

Первым делом нужно сообщить БСП, что наш новый документ должен участвовать в механизме RLS. Это делается через расширение процедуры ПриЗаполненииСписковСОграничениемДоступа в общем модуле УправлениеДоступомПереопределяемый.


&После("ПриЗаполненииСписковСОграничениемДоступа")
Процедура СЮ_ПриЗаполненииСписковСОграничениемДоступа(Списки)
    Списки.Вставить(Метаданные.Документы.НарядЗаказ, Истина);
КонецПроцедуры

Этот код добавляет наш документ НарядЗаказ в список объектов, для которых будут применяться ограничения доступа.

Шаг 2. Описание видов ограничений для объекта

Далее необходимо указать, по каким "разрезам" (видам доступа) будет ограничиваться доступ. В нашем случае это Организации и Подразделения. Для этого расширяем процедуру ПриЗаполненииВидовОграниченийПравОбъектовМетаданных в том же модуле.


&После("ПриЗаполненииВидовОграниченийПравОбъектовМетаданных")
Процедура СЮ_ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(Описание)
    Описание = Описание + 
        "|Документ.НарядЗаказ.Чтение.Подразделения " +
        "|Документ.НарядЗаказ.Чтение.Организации " +
        "|";
КонецПроцедуры

Здесь мы сообщаем системе, что для чтения документа НарядЗаказ будут использоваться виды доступа "Подразделения" и "Организации".

Шаг 3. Настройка шаблона ограничения в роли

В конфигураторе, в нужной роли, на закладке "Ограничения доступа" необходимо прописать шаблон, который будет использоваться для построения запроса RLS. Для БСП используется универсальный шаблон #ПоЗначениямРасширенный. Автор попытался составить условие "ИЛИ" прямо в параметрах шаблона.


#ПоЗначениямРасширенный(
    "Документ.НарядЗаказ",
    "Чтение",
    "", "", "",
    "Организации", "Т.Организация",
    "И(", "Подразделения", "Т.Подразделение",
    "ИЛИ", "Подразделения", "Т.ПодразделениеПолучателя)",
    "", "", "", "", "", "", "", "",
    "", "", "", "", "", "", "", "",
    "", "", "", "", "", "", "", "",
    "", "", "", "", "", "", "", "",
    "", "", ""
)

Этот шаблон должен был сгенерировать конструкцию вида ... ГДЕ Т.Организация В (&РазрешенныеОрганизации) И (Т.Подразделение В (&РазрешенныеПодразделения) ИЛИ Т.ПодразделениеПолучателя В (&РазрешенныеПодразделения)).

Шаг 4. Программное формирование текста запроса

Это самый важный шаг для сложных условий. В модуле менеджера нашего документа НарядЗаказ необходимо создать процедуру ПриЗаполненииОграниченияДоступа. Текст, который мы здесь формируем, имеет наивысший приоритет и будет использован системой для генерации итогового запроса RLS.


Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт
    Ограничение.Текст = 
        "РазрешитьЧтениеИзменение
        |ГДЕ
        |    ЗначениеРазрешено(Организация)
        |    И (ЗначениеРазрешено(Подразделение) ИЛИ ЗначениеРазрешено(ПодразделениеПолучателя))";
КонецПроцедуры

Здесь используется функция БСП ЗначениеРазрешено(), которая является предпочтительным способом проверки доступа в RLS. Конструкция (ЗначениеРазрешено(Подразделение) ИЛИ ЗначениеРазрешено(ПодразделениеПолучателя)) абсолютно корректно описывает нашу бизнес-задачу.

Анализ ошибок и почему стандартный подход не сработал

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

Невозможно обновить ключ доступа объекта "Наряд-заказ..." типа "Наряд-заказ", так как этот тип не указан в определяемом типе ВладелецЗначенийКлючейДоступа.

Это критически важный момент. Ошибка говорит о том, что мы пропустили один из обязательных шагов при добавлении нового объекта в механизм RLS. Для того чтобы система могла кэшировать и хранить рассчитанные права доступа (ключи доступа), тип нашего объекта должен быть включен в состав определяемого типа ВладелецЗначенийКлючейДоступа.

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

Альтернативный подход: модификация типового запроса RLS

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

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

Рассмотрим пример. Допустим, типовой текст запроса RLS для документа выглядит так:


Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт
    Ограничение.Текст = 
    "РазрешитьЧтение
    |ГДЕ
    |    ЗначениеРазрешено(Организация)
    |    И ЗначениеРазрешено(ХозяйственнаяОперация)";
КонецПроцедуры

Мы хотим добавить к нему проверку по подразделению. Создаем в расширении в общем модуле процедуру-обработчик:


&После("ПриЗаполненииОграниченияДоступа")
Процедура XXX_ПриЗаполненииОграниченияДоступа(Ограничение)
    // Проверяем, что работаем именно с нужным нам объектом, чтобы не сломать другие
    Если НЕ ТипЗнч(Ограничение.Источник) = Тип("ДокументМенеджер.ПоступлениеБезналичныхДенежныхСредств") Тогда
        Возврат;
    КонецЕсли;

    Ограничение.Текст = СтрЗаменить(Ограничение.Текст, 
        "ЗначениеРазрешено(ХозяйственнаяОперация)", 
        "ЗначениеРазрешено(ХозяйственнаяОперация) И ЗначениеРазрешено(Подразделение)");
КонецПроцедуры

Что здесь происходит?

  1. Процедура с аннотацией &После выполняется сразу после оригинальной процедуры ПриЗаполненииОграниченияДоступа.
  2. В параметре Ограничение.Текст мы получаем уже сформированный типовой текст запроса.
  3. С помощью функции СтрЗаменить() мы находим в этом тексте известную нам строку (ЗначениеРазрешено(ХозяйственнаяОперация)) и заменяем ее на новую, в которую добавлено наше условие через И.

Такой подход имеет несколько преимуществ:

Выводы и лучшие практики

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

  1. Полный чек-лист для нового объекта:
    • Добавить объект в ПриЗаполненииСписковСОграничениемДоступа.
    • Описать виды доступа в ПриЗаполненииВидовОграниченийПравОбъектовМетаданных.
    • Обязательно добавить тип объекта в определяемый тип ВладелецЗначенийКлючейДоступа.
    • Написать логику в процедуре ПриЗаполненииОграниченияДоступа в модуле менеджера объекта.
  2. Не изменяйте типовые роли. Как справедливо замечено в обсуждении, лучшей практикой является создание новой роли путем копирования типовой. Вносите все изменения в новую роль. Это гарантирует, что при обновлении конфигурации вы не потеряете свои настройки и всегда сможете вернуться к стандартному поведению системы.
  3. Используйте программное формирование запроса. Для любых нетривиальных условий (таких как "ИЛИ" по нескольким полям) самым надежным способом является написание текста запроса в процедуре ПриЗаполненииОграниченияДоступа. Это дает полный контроль над логикой и избавляет от сложностей с синтаксисом шаблонов в ролях.
  4. Рассмотрите модификацию вместо полной замены. Если вам нужно лишь немного дополнить типовую логику RLS, подход с &После и СтрЗаменить может оказаться более простым и надежным в долгосрочной перспективе.

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

← На главную