Как настроить ограничение доступа по иерархии в справочнике Номенклатура в 1С?

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

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

Почему условие «ГДЕ Родитель В (&Параметр)» блокирует доступ

Попытка передать в параметр сеанса ссылку на разрешенную корневую группу и написать простое условие по полю Родитель приводит к тому, что список номенклатуры становится полностью пустым. Выясним причину такого поведения платформы:

  1. Отсечение корневого узла: у самой корневой группы реквизит Родитель не заполнен (является пустой ссылкой), поэтому платформа блокирует чтение самого верхнего каталога.
  2. Блокировка глубоких уровней: у элементов, находящихся на 2-м и последующих уровнях вложенности, значением реквизита Родитель является промежуточная подпапка, а не ссылка из параметра сеанса. В результате такие элементы также не проходят проверку.
  3. Особенности построения дерева: если табличное поле формы работает в режиме иерархического просмотра, недоступность родительских узлов полностью блокирует отображение всей подчиненной ветки.

Способ 1. Интерфейсное ограничение без использования RLS

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

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

Для жесткого ограничения области навигации пользователя конкретной веткой используем свойство НачальныйУзел табличного поля. Разберем пример кода в процедуре ПриОткрытии формы списка:


Процедура ПриОткрытии()
    ПапкаТовары = Справочники.Номенклатура.НайтиПоНаименованию("Товары");
    Если ЗначениеЗаполнено(ПапкаТовары) Тогда
        ЭлементыФормы.СправочникСписок.НачальныйУзел = ПапкаТовары;
    КонецЕсли;
КонецПроцедуры

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

Если же требуется стандартный отбор, можно применить программную установку фильтра по иерархии:


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

При использовании обычного отбора по иерархии соседние корневые папки могут оставаться в дереве в виде пустых узлов, поэтому свойство НачальныйУзел для обычных форм является более предпочтительным.

Способ 2. RLS с проверкой фиксированного количества уровней

Если доступ необходимо закрыть на уровне СУБД, рассмотрим вариант построения RLS-запроса с перебором уровней вложенности через разыменование поля Родитель. Этот способ подходит для баз данных с небольшой глубиной иерархии (до 3–5 уровней).

Посмотрим на пример текста ограничения RLS с возможностью гибкого включения через параметр сеанса и проверкой прав по регистру сведений:


Справочник.Номенклатура КАК спр
ГДЕ НЕ &ТекущиеОграничения ИЛИ (
    спр.Ссылка В (
        ВЫБРАТЬ РАЗЛИЧНЫЕ Права.ОбъектДоступа
        ИЗ РегистрСведений.ПраваДоступаПользователей КАК Права
        ГДЕ Права.Пользователь В (&ГруппыТекущегоПользователя)
    )
    ИЛИ спр.Родитель В (
        ВЫБРАТЬ РАЗЛИЧНЫЕ Права.ОбъектДоступа
        ИЗ РегистрСведений.ПраваДоступаПользователей КАК Права
        ГДЕ Права.Пользователь В (&ГруппыТекущегоПользователя)
        И Права.ВидНаследованияПравДоступаИерархическихСправочников = ЗНАЧЕНИЕ(Перечисление.ВидыНаследованияПравДоступаИерархическихСправочников.РаспространитьНаПодчиненных)
    )
    ИЛИ спр.Родитель.Родитель В (
        ВЫБРАТЬ РАЗЛИЧНЫЕ Права.ОбъектДоступа
        ИЗ РегистрСведений.ПраваДоступаПользователей КАК Права
        ГДЕ Права.Пользователь В (&ГруппыТекущегоПользователя)
        И Права.ВидНаследованияПравДоступаИерархическихСправочников = ЗНАЧЕНИЕ(Перечисление.ВидыНаследованияПравДоступаИерархическихСправочников.РаспространитьНаПодчиненных)
    )
    ИЛИ спр.Родитель.Родитель.Родитель В (
        ВЫБРАТЬ РАЗЛИЧНЫЕ Права.ОбъектДоступа
        ИЗ РегистрСведений.ПраваДоступаПользователей КАК Права
        ГДЕ Права.Пользователь В (&ГруппыТекущегоПользователя)
        И Права.ВидНаследованияПравДоступаИерархическихСправочников = ЗНАЧЕНИЕ(Перечисление.ВидыНаследованияПравДоступаИерархическихСправочников.РаспространитьНаПодчиненных)
    )
)

Важный нюанс: цепочки разыменования Родитель.Родитель... приводят к множественным неявным левым соединениям (LEFT JOIN) таблицы с самой собой на уровне SQL-сервера. Использование операторов ИЛИ между соединениями делает невозможным эффективное использование индексов СУБД, вызывая сканирование таблиц (Table Scan / Index Scan) при каждом запросе.

Способ 3. Оптимальный RLS через разворачивание иерархии (транзитивное замыкание)

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

Разберем структуру и логику работы этого метода:

  1. Структура регистра: создаем измерения Объект (тип СправочникСсылка.Номенклатура) и Предок (тип СправочникСсылка.Номенклатура).
  2. Заполнение данных: для каждого элемента или папки в регистр записываются строки со всеми вышестоящими родительскими группами любого уровня вложенности, а также строка, где объект ссылается сам на себя. Поддержание актуальности выполняется через подписку на событие ПриЗаписи справочника Номенклатура.
  3. Текст RLS-запроса: запрос ограничения сводится к одному быстрому соединению по индексированным полям:

Справочник.Номенклатура КАК спр
ГДЕ спр.Ссылка В (
    ВЫБРАТЬ Иерархия.Объект
    ИЗ РегистрСведений.СоставИерархииНоменклатуры КАК Иерархия
    ГДЕ Иерархия.Предок В (&ДоступныеПапки)
)

Такой подход обеспечивает максимальное быстродействие запросов на стороне СУБД, устраняет необходимость сложных конструкций с ИЛИ и корректно отрабатывает иерархию любой глубины.

Рекомендации по разделению прав на чтение и запись

При полном закрытии чтения элементов номенклатуры через RLS неизбежно возникают побочные эффекты:

  1. В общих документах (например, проведенных другими пользователями) строки с недоступными товарами отображаются как «Объект не найден».
  2. Пользователи не могут корректно перепроводить или копировать такие документы.
  3. В отчетах по продажам и остаткам возникают расхождения и пустые строки.

Если задача заключается исключительно в том, чтобы запретить пользователям выбирать и продавать определенные позиции, рекомендуется оставлять право Чтение без ограничений, а правила RLS или программные проверки в подписке на событие ПередЗаписью устанавливать только для прав Добавление и Изменение.

← На главную