При работе пользователей с ограниченными правами в программах 1С нередко возникает ситуация, когда при попытке открыть элемент справочника (например, Контрагенты) система аварийно прерывает работу с ошибкой «Нарушение прав доступа!». При этом ошибка указывает на строку программного кода в модуле формы, где происходит чтение регистра сведений.
Проанализируем ситуацию на типовом примере из практики. В процедуре установки видимости элементов формы выполняется следующий код:
Процедура УстановитьВидимостьДоступность()
НаборЗаписей = РегистрыСведений.БП_ЧерныйСписокКлиентов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Клиент.Установить(Ссылка);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() > 0 Тогда
ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.ВЧерномСписке;
ПричинаЧерныйСписок = НаборЗаписей[0].Причина;
Иначе
ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.НеВЧерномСписке;
КонецЕсли;
ЭлементыФормы.Панель.Страницы.БП_АдресаДоставки.Видимость = Ложь;
КонецПроцедуры
В момент вызова метода НаборЗаписей.Прочитать() платформа выбрасывает исключение. Выясним причину такого поведения и разберем варианты решения проблемы — от настройки прав до оптимизации программного кода.
Ошибка вызвана тем, что у роли, назначенной текущему пользователю, отсутствует базовое право Чтение на регистр сведений БП_ЧерныйСписокКлиентов. Даже если у пользователя есть полные права на сам справочник Контрагенты, обращение к связанным объектам конфигурации в коде формы напрямую проверяется механизмом контроля доступа платформы 1С:Предприятие.
Нередко разработчики и администраторы путают имя объекта метаданных с его синонимом. В пользовательском интерфейсе объект может называться «Черный список клиентов», тогда как в дереве метаданных конфигуратора его реальное имя — БП_ЧерныйСписокКлиентов.
Разберем по шагам стандартное администрирование прав доступа через конфигуратор:
БП_ЧерныйСписокКлиентов.МенеджерПоПродажам).После предоставления права на чтение метод НаборЗаписей.Прочитать() выполнится успешно, и форма контрагента откроется без ошибок.
Если рядовому пользователю не положено знать о наличии регистра сведений и администратор намеренно не выдает на него права, форму необходимо защитить от падения. Для этого используем функцию ПравоДоступа():
Процедура УстановитьВидимостьДоступность()
// Проверяем наличие права на чтение объекта метаданных
Если ПравоДоступа("Чтение", Метаданные.РегистрыСведений.БП_ЧерныйСписокКлиентов) Тогда
НаборЗаписей = РегистрыСведений.БП_ЧерныйСписокКлиентов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Клиент.Установить(Ссылка);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() > 0 Тогда
ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.ВЧерномСписке;
ПричинаЧерныйСписок = НаборЗаписей[0].Причина;
Иначе
ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.НеВЧерномСписке;
КонецЕсли;
Иначе
// Если прав нет, просто скрываем или переключаем интерфейсную панель
ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.НеВЧерномСписке;
КонецЕсли;
ЭлементыФормы.Панель.Страницы.БП_АдресаДоставки.Видимость = Ложь;
КонецПроцедуры
В ситуациях, когда интерфейс должен отображать статус блокировки контрагента любому пользователю, но открывать прямой доступ ко всему регистру нежелательно, правильнее использовать привилегированный контекст.
Посмотрим на реализацию через функцию в общем модуле с установленным свойством Привилегированный:
// В привилегированном общем модуле
Функция ПолучитьСведенияОЧерномСписке(КонтрагентСсылка) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ЧерныйСписок.Причина КАК Причина
|ИЗ
| РегистрСведений.БП_ЧерныйСписокКлиентов КАК ЧерныйСписок
|ГДЕ
| ЧерныйСписок.Клиент = &Клиент";
Запрос.УстановитьПараметр("Клиент", КонтрагентСсылка);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Новый Структура("ВЧерномСписке, Причина", Истина, Выборка.Причина);
Иначе
Возврат Новый Структура("ВЧерномСписке, Причина", Ложь, "");
КонецЕсли;
КонецФункции
Вызов запроса в привилегированном режиме работает значительно быстрее создания набора записей СоздатьНаборЗаписей(), не требует выделения полных прав пользователю на регистр и гарантирует стабильное открытие формы контрагента.
Если регистр сведений непериодический и имеет единственное измерение Клиент, вместо чтения громоздкого набора записей рекомендуется использовать метод менеджера Получить() (либо метод СрезПоследних() для периодического регистра):
Отбор = Новый Структура("Клиент", Ссылка);
ЗначенияРесурсов = РегистрыСведений.БП_ЧерныйСписокКлиентов.Получить(Отбор);
Если ЗначениеЗаполнено(ЗначенияРесурсов.Причина) Тогда
ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.ВЧерномСписке;
ПричинаЧерныйСписок = ЗначенияРесурсов.Причина;
Иначе
ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.НеВЧерномСписке;
КонецЕсли;
Такой подход делает код чище, производительнее и проще в отладке.