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