В процессе настройки прав доступа в 1С часто возникает задача: предоставить пользователю права не только на те объекты, которые указаны в его группе доступа, но и на связанные с ними. Классический пример — иерархия организаций. Пользователь имеет доступ к своему филиалу (обособленному подразделению), но для корректной работы ему нужно видеть и родительскую, головную организацию, доступ к которой напрямую не открыт.
Рассмотрим, как решить эту задачу с помощью механизма ограничения доступа на уровне записей (RLS), и разберемся в ключевых функциях, которые используются в запросах ограничений: ЗначениеРазрешено() и ЧтениеОбъектаРазрешено().
Проанализируем исходную ситуацию. Есть регистр сведений, где доступ к записям определяется по двум измерениям:
"РазрешитьЧтениеИзменение
|ГДЕ
| ЗначениеРазрешено(ГоловнаяОрганизация)
| И
ЗначениеРазрешено(ФизическоеЛицо)";
И есть справочник «Организации», где права настраиваются так:
"РазрешитьЧтение
|Где Ссылка.ЕстьОбособленныеПодразделения
|или ЧтениеОбъектаРазрешено(Ссылка)
|;
|РазрешитьИзменениеЕслиРазрешеноЧтение
|ГДЕ
| ЗначениеРазрешено(Ссылка)";
Главный вопрос автора: если у пользователя нет прямого доступа к головной организации (то есть ЗначениеРазрешено(ГоловнаяОрганизация) вернет ЛОЖЬ), но он видит ее благодаря другому условию, сможет ли он создать запись в регистре с этой организацией? Ответ — нет, не сможет. Запись в регистр будет заблокирована, так как его RLS-правило жестко требует прямого разрешения на головную организацию.
Чтобы решить эту проблему, нужно понять разницу в работе двух основных функций проверки прав в RLS.
На первый взгляд, синтаксис этих функций похож, но механически они работают совершенно по-разному. Это фундаментальный момент для понимания и отладки RLS.
ЗначениеРазрешено(<Поле>)
Эта функция выполняет простую и очень быструю проверку. Она обращается к заранее подготовленному для сеанса пользователя списку разрешенных значений по определенному виду доступа (например, «Организации»).
ЧтениеОбъектаРазрешено(<Поле>)
Эта функция запускает сложный, рекурсивный механизм проверки. Она не смотрит в готовые списки, а по сути, заново выполняет весь RLS-запрос, определенный для объекта, на который указывает поле.
ЧтениеОбъектаРазрешено(СсылкаНаОрганизацию) будет выполнен весь этот сложный запрос.ЗначениеРазрешено(). Использование этой функции может приводить к серьезным замедлениям на больших объемах данных, так как она порождает вложенные проверки.Как отметил автор темы, функции совсем не "так же" работают. ЗначениеРазрешено() — это проверка по списку из групп доступа, а ЧтениеОбъектаРазрешено() — это проверка через выполнение RLS-правила самого объекта.
Итак, наша задача — разрешить чтение организации, если она является головной для той организации, к которой у пользователя есть прямой доступ. Стандартные функции тут не помогут, так как они не умеют анализировать связи между объектами. Решение — использовать соединение таблиц прямо в тексте запроса ограничения доступа.
Изменим шаблон RLS для справочника «Организации» следующим образом.
Шаг 1. Добавляем соединение таблиц.
Нам нужно соединить таблицу организаций саму с собой, чтобы для каждой организации (назовем ее `Т`) найти те организации (`Т2`), у которых она указана как головная. Для этого используем конструкцию ПрисоединитьДополнительныеТаблицы.
"ПрисоединитьДополнительныеТаблицы
| ЭтотСписок КАК Т
| Левое Соединение Справочник.Организации КАК Т2
| По Т.ссылка = Т2.ГоловнаяОрганизация
|
|;
Разберем этот код:
ЭтотСписок КАК Т: ЭтотСписок — это специальный псевдоним для основной таблицы, к которой применяется ограничение. Мы даем ей короткое имя `Т`.Левое Соединение Справочник.Организации КАК Т2: Присоединяем к нашей таблице `Т` еще раз таблицу организаций под псевдонимом `Т2`.По Т.ссылка = Т2.ГоловнаяОрганизация: Условие соединения. Мы связываем запись из `Т` (потенциальная головная организация) с записью из `Т2` (обособленное подразделение), у которого в реквизите `ГоловнаяОрганизация` указана ссылка на `Т`.В результате для каждой строки из `Т`, которая является головной, в `Т2` мы получим связанные с ней обособленные подразделения.
Шаг 2. Формулируем условие разрешения чтения.
Теперь, когда у нас есть связанные данные, мы можем написать условие. Пользователь должен видеть организацию (`Т.Ссылка`) в двух случаях:
Запишем это в секции РазрешитьЧтение.
"РазрешитьЧтение
|Где ЗначениеРазрешено(Т2.Ссылка)
|или ЗначениеРазрешено(Т.Ссылка)
|;
ЗначениеРазрешено(Т2.Ссылка) — это и есть наше решение. Мы проверяем право доступа не на текущую организацию, а на связанное с ней обособленное подразделение. Если у пользователя есть доступ хотя бы к одному подразделению, то он увидит и его головную организацию.или ЗначениеРазрешено(Т.Ссылка) — это стандартное правило, которое оставляет пользователю прямой доступ к организациям из его групп доступа.Шаг 3. Собираем итоговый запрос RLS.
Объединим все части и добавим стандартное правило для изменения. Итоговый текст ограничения для справочника «Организации» будет выглядеть так:
"ПрисоединитьДополнительныеТаблицы
| ЭтотСписок КАК Т
| Левое Соединение Справочник.Организации КАК Т2
| По Т.ссылка = Т2.ГоловнаяОрганизация
|
|;
|РазрешитьЧтение
|Где ЗначениеРазрешено(Т2.Ссылка)
|или ЗначениеРазрешено(Т.Ссылка)
|;
|РазрешитьИзменениеЕслиРазрешеноЧтение
|ГДЕ
| ЗначениеРазрешено(Ссылка)";
Вернемся к изначальному вопросу: сможет ли пользователь теперь записать документ с головной организацией? После того как мы изменили RLS для справочника «Организации», пользователь сможет выбрать эту организацию в поле ввода. Но сама запись в регистр регулируется RLS регистра сведений.
Чтобы разрешить и запись, нужно модифицировать RLS регистра, используя ту же логику, или применить функцию `ЧтениеОбъектаРазрешено`, которая теперь будет использовать наш новый сложный механизм проверки:
"РазрешитьЧтениеИзменение
|ГДЕ
| ЧтениеОбъектаРазрешено(ГоловнаяОрганизация) // Эта функция запустит RLS для справочника "Организации"
| И ЗначениеРазрешено(ФизическоеЛицо)";
Важно: Помните о производительности. Использование ЧтениеОбъектаРазрешено в RLS для часто используемых регистров может замедлить систему. В таких случаях может быть эффективнее продублировать логику с JOIN и в RLS для регистра.
Для отладки подобных сложных правил RLS незаменимым инструментом является Технологический журнал 1С. Он позволяет увидеть итоговый SQL-запрос, который платформа отправляет в базу данных, и понять, какие именно условия применяются к выборке данных.