Как в 1С настроить RLS для доступа к головной организации, если есть доступ только к подразделению?

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

В процессе настройки прав доступа в 1С часто возникает задача: предоставить пользователю права не только на те объекты, которые указаны в его группе доступа, но и на связанные с ними. Классический пример — иерархия организаций. Пользователь имеет доступ к своему филиалу (обособленному подразделению), но для корректной работы ему нужно видеть и родительскую, головную организацию, доступ к которой напрямую не открыт.

Рассмотрим, как решить эту задачу с помощью механизма ограничения доступа на уровне записей (RLS), и разберемся в ключевых функциях, которые используются в запросах ограничений: ЗначениеРазрешено() и ЧтениеОбъектаРазрешено().

Анализ проблемы: почему стандартные шаблоны не работают?

Проанализируем исходную ситуацию. Есть регистр сведений, где доступ к записям определяется по двум измерениям:


"РазрешитьЧтениеИзменение
|ГДЕ
|	ЗначениеРазрешено(ГоловнаяОрганизация)
|	И
 ЗначениеРазрешено(ФизическоеЛицо)";

И есть справочник «Организации», где права настраиваются так:


"РазрешитьЧтение
|Где Ссылка.ЕстьОбособленныеПодразделения
|или ЧтениеОбъектаРазрешено(Ссылка)
|;
|РазрешитьИзменениеЕслиРазрешеноЧтение
|ГДЕ
|	ЗначениеРазрешено(Ссылка)";

Главный вопрос автора: если у пользователя нет прямого доступа к головной организации (то есть ЗначениеРазрешено(ГоловнаяОрганизация) вернет ЛОЖЬ), но он видит ее благодаря другому условию, сможет ли он создать запись в регистре с этой организацией? Ответ — нет, не сможет. Запись в регистр будет заблокирована, так как его RLS-правило жестко требует прямого разрешения на головную организацию.

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

Ключевое различие: ЗначениеРазрешено() vs ЧтениеОбъектаРазрешено()

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

ЗначениеРазрешено(<Поле>)

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

ЧтениеОбъектаРазрешено(<Поле>)

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

Как отметил автор темы, функции совсем не "так же" работают. ЗначениеРазрешено() — это проверка по списку из групп доступа, а ЧтениеОбъектаРазрешено() — это проверка через выполнение RLS-правила самого объекта.

Решение: настраиваем доступ к головным организациям через JOIN

Итак, наша задача — разрешить чтение организации, если она является головной для той организации, к которой у пользователя есть прямой доступ. Стандартные функции тут не помогут, так как они не умеют анализировать связи между объектами. Решение — использовать соединение таблиц прямо в тексте запроса ограничения доступа.

Изменим шаблон RLS для справочника «Организации» следующим образом.

Шаг 1. Добавляем соединение таблиц.

Нам нужно соединить таблицу организаций саму с собой, чтобы для каждой организации (назовем ее `Т`) найти те организации (`Т2`), у которых она указана как головная. Для этого используем конструкцию ПрисоединитьДополнительныеТаблицы.


"ПрисоединитьДополнительныеТаблицы
|	ЭтотСписок КАК Т
|	Левое Соединение Справочник.Организации КАК Т2
|	По Т.ссылка = Т2.ГоловнаяОрганизация
|
|;

Разберем этот код:

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

Шаг 2. Формулируем условие разрешения чтения.

Теперь, когда у нас есть связанные данные, мы можем написать условие. Пользователь должен видеть организацию (`Т.Ссылка`) в двух случаях:

  1. Если у него есть доступ к ее дочерней организации (`Т2.Ссылка`).
  2. Если у него есть прямой доступ к самой этой организации (`Т.Ссылка`).

Запишем это в секции РазрешитьЧтение.


"РазрешитьЧтение
|Где ЗначениеРазрешено(Т2.Ссылка)
|или ЗначениеРазрешено(Т.Ссылка)
|;

Шаг 3. Собираем итоговый запрос RLS.

Объединим все части и добавим стандартное правило для изменения. Итоговый текст ограничения для справочника «Организации» будет выглядеть так:


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

Что делать с правами на запись?

Вернемся к изначальному вопросу: сможет ли пользователь теперь записать документ с головной организацией? После того как мы изменили RLS для справочника «Организации», пользователь сможет выбрать эту организацию в поле ввода. Но сама запись в регистр регулируется RLS регистра сведений.

Чтобы разрешить и запись, нужно модифицировать RLS регистра, используя ту же логику, или применить функцию `ЧтениеОбъектаРазрешено`, которая теперь будет использовать наш новый сложный механизм проверки:


"РазрешитьЧтениеИзменение
|ГДЕ
|	ЧтениеОбъектаРазрешено(ГоловнаяОрганизация) // Эта функция запустит RLS для справочника "Организации"
|	И ЗначениеРазрешено(ФизическоеЛицо)";

Важно: Помните о производительности. Использование ЧтениеОбъектаРазрешено в RLS для часто используемых регистров может замедлить систему. В таких случаях может быть эффективнее продублировать логику с JOIN и в RLS для регистра.

Для отладки подобных сложных правил RLS незаменимым инструментом является Технологический журнал 1С. Он позволяет увидеть итоговый SQL-запрос, который платформа отправляет в базу данных, и понять, какие именно условия применяются к выборке данных.

← На главную