При разработке конфигураций на платформе «1С:Предприятие 8» одной из важнейших задач является обеспечение безопасности и корректного разграничения прав доступа. Довольно часто разработчики сталкиваются с ситуацией, когда программный код обращается к объектам метаданных (например, регистрам сведений, справочникам или документам), на чтение которых у текущего пользователя нет прав. В этой статье мы подробно разберем, как ведет себя платформа при вызове метода Выбрать(), в чем заключается коварство ключевого слова РАЗРЕШЕННЫЕ в запросах, и как правильно реализовать проверку прав, чтобы избежать аварийного завершения работы программы.
Если у пользователя в его ролях полностью отсутствует право «Чтение» на определенный регистр сведений, то при попытке вызвать метод РегистрСведений.ИмяРегистра.Выбрать() платформа «1С:Предприятие 8» всегда генерирует исключение (ошибку выполнения) «Нарушение прав доступа».
Никакой пустой выборки в данном случае возвращено не будет. Платформа блокирует обращение к таблице базы данных на самом раннем этапе. Если этот вызов не обернут в блок обработки исключений, программа пользователя аварийно завершит текущую операцию, что крайне негативно сказывается на стабильности системы.
Среди начинающих разработчиков распространено заблуждение, что любые проблемы с правами доступа к таблицам можно решить использованием ключевого слова РАЗРЕШЕННЫЕ в запросах. Давайте проанализируем ситуацию и выясним истинную физику этого процесса.
Ключевое слово РАЗРЕШЕННЫЕ работает исключительно на уровне ограничений доступа к записям (RLS — Row-Level Security). Это означает следующее:
РАЗРЕШЕННЫЕ вызовет ошибку доступа при первой же попытке прочесть «чужую» строку. Если же в запросе указано слово РАЗРЕШЕННЫЕ, платформа молча отфильтрует недоступные строки и вернет пустой или частично заполненный результат без генерации ошибок.РАЗРЕШЕННЫЕ) еще на этапе компиляции схемы запроса. Система сразу выбросит исключение «Нарушение прав доступа».Чтобы избежать аварийного завершения работы программы и не использовать ресурсоемкие конструкции Попытка ... Исключение для логического ветвления программного кода, необходимо выполнять предварительную проверку прав текущего пользователя.
Для этого в платформе существует встроенный метод ПравоДоступа(). Рассмотрим стандартный шаблон проверки:
Если ПравоДоступа("Чтение", Метаданные.РегистрыСведений.ИмяВашегоРегистра) Тогда
// Безопасное чтение данных
Выборка = РегистрыСведений.ИмяВашегоРегистра.Выбрать();
Пока Выборка.Следующий() Цикл
// Обработка данных
КонецЦикла;
Иначе
// Альтернативная логика или уведомление пользователя
ВызватьИсключение "У вас недостаточно прав для выполнения этой операции.";
КонецЕсли;
Существует критически важная деталь, о которой часто забывают даже опытные разработчики. Если вышеуказанный код выполняется на стороне сервера в привилегированном режиме (например, внутри привилегированного общего модуля или после явного вызова УстановитьПривилегированныйРежим(Истина)), метод ПравоДоступа() с двумя параметрами всегда вернет Истина.
Это происходит потому, что платформа считает текущий контекст выполнения доверенным и не накладывает ограничения текущего сеанса. Но если дальше по коду данные будут передаваться на клиент или обрабатываться логикой, завязанной на реальные права пользователя, это может привести к уязвимостям или ошибкам.
Чтобы узнать реальные права текущего пользователя, находясь в привилегированном контексте, необходимо обязательно передавать третьим параметром конкретного пользователя информационной базы:
ТекущийПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
ЕстьДоступ = ПравоДоступа("Чтение", Метаданные.РегистрыСведений.ИмяВашегоРегистра, ТекущийПользовательИБ);
Если ЕстьДоступ Тогда
// Чтение разрешено реальному пользователю
КонецЕсли;
Согласно официальным стандартам разработки фирмы «1С», проверять доступность данных через явную проверку ролей (например, с помощью метода РольДоступна("ПолныеПрава")) крайне не рекомендуется для управления логикой доступа к таблицам БД. Роли в процессе обновления или кастомизации конфигурации могут переименовываться, удаляться или разделяться.
Проверять возможность работы с конкретной таблицей всегда нужно через права доступа к объекту метаданных: ПравоДоступа("Чтение", Метаданные.РегистрыСведений.ИмяРегистра). Метод РольДоступна() допускается использовать только для проверки общих административных или сугубо логических прав интерфейса, не связанных напрямую со структурой хранения данных.
Если вы работаете в современной конфигурации, созданной на базе БСП (например, «1С:ERP», «1С:Управление торговлей», «1С:Бухгалтерия»), ручные проверки метаданных лучше заменить на вызовы стандартизированных функций общего модуля УправлениеДоступом.
Рассмотрим два полезных метода:
УправлениеДоступом.ЧтениеРазрешено(ОписаниеДанных) — этот метод проверяет доступность объекта (справочника, документа, регистра) как на уровне метаданных, так и с учетом ограничений RLS. Возвращает булево значение.УправлениеДоступом.ПроверитьЧтениеРазрешено(ОписаниеДанных) — если у пользователя нет прав на чтение, эта процедура сама корректно сгенерирует исключение со стандартным системным текстом ошибки доступа, что избавляет вас от необходимости вручную прописывать генерацию исключений.Пример использования функций БСП в коде:
// Проверяем возможность чтения регистра сведений через БСП
Если УправлениеДоступом.ЧтениеРазрешено(Метаданные.РегистрыСведений.ИмяВашегоРегистра) Тогда
// Чтение разрешено, выполняем безопасный запрос
Иначе
// Обработка ситуации отсутствия прав
КонецЕсли;
В некоторых случаях бизнес-логика требует, чтобы алгоритм (например, проведение документа или формирование сложного аналитического отчета) обязательно прочитал данные из регистра сведений, к которому у рядового пользователя нет и не должно быть прямого доступа (например, регистры сведений с техническими настройками, ключевыми параметрами расчета себестоимости или персональными данными).
В таких сценариях лучшей практикой проектирования систем на платформе «1С:Предприятие 8» является вынос логики чтения данных в привилегированные общие модули либо программное включение привилегированного режима перед чтением:
УстановитьПривилегированныйРежим(Истина);
// Выполняем выборку или запрос к закрытому регистру сведений "под капотом" системы
Выборка = РегистрыСведений.ТехническиеНастройкиСистемы.Выбрать();
// Обрабатываем служебные данные для проведения документа...
УстановитьПривилегированныйРежим(Ложь);
Использование этого подхода позволяет безопасно выполнять необходимые расчеты и при этом не открывать пользователям лишние права на чтение конфиденциальных бизнес-данных напрямую из интерфейса программы.