Почему запрос с конструкцией ВЫБРАТЬ РАЗРЕШЕННЫЕ выдает ошибку прав доступа?

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

Часто разработчики 1С сталкиваются с непредвиденным поведением платформы: при выполнении запроса, в котором используется конструкция РАЗРЕШЕННЫЕ, система прерывает работу и выдает ошибку вида "Недостаточно прав для работы с таблицей". Разберем эту ситуацию по шагам, выясним причину такого поведения и проанализируем, как правильно обрабатывать подобные сценарии, чтобы конечный пользователь не сталкивался с пугающими системными сообщениями.

Ошибочное понимание конструкции РАЗРЕШЕННЫЕ

Многие полагают, что использование ключевого слова РАЗРЕШЕННЫЕ в начале запроса делает его полностью безопасным с точки зрения прав доступа. Кажется логичным: если у пользователя нет прав на какие-то данные, платформа должна просто скрыть их из результата выборки, вернув пустой результат или только те строки, которые разрешены. Однако это работает не совсем так.

Проанализируем механику работы платформы. Платформа 1С различает два уровня прав доступа:

  1. Базовые права на метаданные (таблицы): Задаются в ролях пользователя флагами "Чтение", "Добавление", "Изменение" и т.д. для всего объекта (например, документа ЗаявкиНаЛьготныйКредит).
  2. Ограничение доступа на уровне записей (RLS): Задаются там же, в ролях, но в виде специальных условий, которые определяют, какие именно элементы таблицы (записи) может видеть пользователь (например, только документы своей организации).

Слово РАЗРЕШЕННЫЕ обрабатывает только ограничения RLS. Если у пользователя вообще нет базового права "Чтение" на запрашиваемую таблицу, запрос упадет с ошибкой "Недостаточно прав" еще до того, как платформа попытается применить RLS. Платформа проверяет наличие базовых прав на таблицы метаданных на этапе компиляции запроса. Если права нет в принципе — запрос не может быть выполнен, и конструкция РАЗРЕШЕННЫЕ здесь бессильна.

Как это работает под капотом СУБД

Давайте посмотрим, как платформа транслирует запросы к СУБД в зависимости от наличия ключевого слова:

Без ключевого слова РАЗРЕШЕННЫЕ: СУБД выполняет запрос и добавляет специальную скрытую колонку-индикатор. Эта колонка определяет, доступна ли конкретная строка пользователю по правилам RLS. Если в процессе чтения выборки платформа натыкается на строку с флагом "запрещено", выполнение немедленно прерывается исключением.

С ключевым словом РАЗРЕШЕННЫЕ: Условия RLS транслируются непосредственно в секцию WHERE SQL-запроса (что часто превращается в сложные подзапросы). СУБД фильтрует данные на своей стороне и отдает серверу 1С только разрешенные записи. Исключения не возникает, так как запрещенные строки просто отсекаются на уровне базы данных. Это может усложнять план выполнения и влиять на производительность, но позволяет избежать падения кода.

Особенности работы при обращении к полям "через точку"

Рассмотрим ситуацию, когда ошибки прав возникают "неожиданно". Одна из самых частых причин падения запросов с РАЗРЕШЕННЫЕ под пользователями с ограниченными правами — это обращение к связанным таблицам через точку (разыменование ссылок).

Если в запросе мы обращаемся к реквизитам связанной таблицы, например ЗаявкиНаЛьготныйКредит.Организация.ИНН, и у пользователя нет доступа к таблице организаций (базового права), платформа не выдаст ошибку, а просто вернет пустое значение (NULL). Однако, если у пользователя нет прав абсолютно на все поля, запрашиваемые через точку, либо отсутствует право чтения самой таблицы, из которой начинается разыменование, запрос упадет.

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


ВЫБРАТЬ РАЗРЕШЕННЫЕ
    ВЫРАЗИТЬ(Таблица.ДокументОснование КАК Документ.ЗаявкиНаЛьготныйКредит).Дата КАК ДатаОснования
ИЗ
    Документ.ПлатежноеПоручение КАК Таблица

Конструкция ВЫРАЗИТЬ отсекает ненужные таблицы, защищая запрос от падения при отсутствии прав на другие типы.

Особенности пакетных и вложенных запросов

Разберем важное правило синтаксиса: ключевое слово РАЗРЕШЕННЫЕ может быть указано только в самом первом предложении ВЫБРАТЬ запроса самого верхнего уровня. Его действие автоматически каскадируется на:

  1. Все вложенные запросы.
  2. Временные таблицы, создаваемые в пакете.
  3. Все запросы, объединяемые конструкцией ОБЪЕДИНИТЬ.

Если попытаться написать ВЫБРАТЬ РАЗРЕШЕННЫЕ во втором запросе пакета или внутри вложенного запроса, платформа выдаст синтаксическую ошибку.

Решения проблемы: программная проверка прав и привилегированный режим

Пользователи никогда не должны видеть системные ошибки "Недостаточно прав". Это подрывает доверие к ИТ-отделу и создает иллюзию нестабильной работы программы. Рассмотрим два основных способа решения проблемы.

1. Программная проверка прав перед выполнением запроса

Если мы не уверены, есть ли у пользователя базовые права на таблицу, нужно проверить это программно. Визуально проверять роли через конфигуратор (как иногда советуют) неэффективно. Используем платформенный метод:


Если ПравоДоступа("Чтение", Метаданные.Документы.ЗаявкиНаЛьготныйКредит) Тогда
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ РАЗЛИЧНЫЕ
                   |    ЗаявкиНаЛьготныйКредит.Организация КАК Организация
                   |ИЗ
                   |    Документ.ЗаявкиНаЛьготныйКредит КАК ЗаявкиНаЛьготныйКредит";
    Результат = Запрос.Выполнить();
Иначе
    // Обрабатываем ситуацию: выводим сообщение или просто пропускаем логику
КонецЕсли;

Если используется БСП (Библиотека стандартных подсистем), можно применить функции программного интерфейса: УправлениеДоступом.ДоступнаТаблица() или Пользователи.РолиДоступны().

2. Использование привилегированного режима

Если по бизнес-логике алгоритм обязан получить эти данные независимо от прав текущего пользователя (например, для служебного расчета или формирования сводных проводок), мы используем привилегированный режим.


УстановитьПривилегированныйРежим(Истина);

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
               |    ЗаявкиНаЛьготныйКредит.Организация КАК Организация
               |ИЗ
               |    Документ.ЗаявкиНаЛьготныйКредит КАК ЗаявкиНаЛьготныйКредит";

Результат = Запрос.Выполнить();

УстановитьПривилегированныйРежим(Ложь);

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

← На главную