Как исправить ошибку «Нарушение прав доступа» при открытии карточки контрагента в 1С?

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

При работе пользователей с ограниченными правами в программах 1С нередко возникает ситуация, когда при попытке открыть элемент справочника (например, Контрагенты) система аварийно прерывает работу с ошибкой «Нарушение прав доступа!». При этом ошибка указывает на строку программного кода в модуле формы, где происходит чтение регистра сведений.

Проанализируем ситуацию на типовом примере из практики. В процедуре установки видимости элементов формы выполняется следующий код:


Процедура УстановитьВидимостьДоступность()
    
    НаборЗаписей = РегистрыСведений.БП_ЧерныйСписокКлиентов.СоздатьНаборЗаписей();     
    НаборЗаписей.Отбор.Клиент.Установить(Ссылка);
    НаборЗаписей.Прочитать();
    Если НаборЗаписей.Количество() > 0 Тогда
        ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.ВЧерномСписке;
        ПричинаЧерныйСписок = НаборЗаписей[0].Причина;
    Иначе
        ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.НеВЧерномСписке;
    КонецЕсли;
    
    ЭлементыФормы.Панель.Страницы.БП_АдресаДоставки.Видимость = Ложь;
    
КонецПроцедуры

В момент вызова метода НаборЗаписей.Прочитать() платформа выбрасывает исключение. Выясним причину такого поведения и разберем варианты решения проблемы — от настройки прав до оптимизации программного кода.

Причина ошибки

Ошибка вызвана тем, что у роли, назначенной текущему пользователю, отсутствует базовое право Чтение на регистр сведений БП_ЧерныйСписокКлиентов. Даже если у пользователя есть полные права на сам справочник Контрагенты, обращение к связанным объектам конфигурации в коде формы напрямую проверяется механизмом контроля доступа платформы 1С:Предприятие.

Нередко разработчики и администраторы путают имя объекта метаданных с его синонимом. В пользовательском интерфейсе объект может называться «Черный список клиентов», тогда как в дереве метаданных конфигуратора его реальное имя — БП_ЧерныйСписокКлиентов.

Способ 1. Настройка прав роли в конфигураторе

Разберем по шагам стандартное администрирование прав доступа через конфигуратор:

  1. Откроем дерево метаданных конфигурации и найдем нужный регистр сведений в ветке Регистры сведений -> БП_ЧерныйСписокКлиентов.
  2. Нажмем правой кнопкой мыши на регистре и выберем пункт Дополнительно либо дважды кликнем по объекту и перейдем на вкладку Права.
  3. Найдем в списке ролей ту роль (или профиль групп доступа), которая назначена проблемному пользователю (например, МенеджерПоПродажам).
  4. Установим флаг для права Чтение (а при необходимости — Просмотр).
  5. Обновим конфигурацию базы данных (по клавише F7).

После предоставления права на чтение метод НаборЗаписей.Прочитать() выполнится успешно, и форма контрагента откроется без ошибок.

Способ 2. Программная проверка прав перед обращением к регистру

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


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

Способ 3. Выполнение проверки в привилегированном режиме

В ситуациях, когда интерфейс должен отображать статус блокировки контрагента любому пользователю, но открывать прямой доступ ко всему регистру нежелательно, правильнее использовать привилегированный контекст.

Посмотрим на реализацию через функцию в общем модуле с установленным свойством Привилегированный:


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

Вызов запроса в привилегированном режиме работает значительно быстрее создания набора записей СоздатьНаборЗаписей(), не требует выделения полных прав пользователю на регистр и гарантирует стабильное открытие формы контрагента.

Способ 4. Получение данных через метод менеджера

Если регистр сведений непериодический и имеет единственное измерение Клиент, вместо чтения громоздкого набора записей рекомендуется использовать метод менеджера Получить() (либо метод СрезПоследних() для периодического регистра):


Отбор = Новый Структура("Клиент", Ссылка);
ЗначенияРесурсов = РегистрыСведений.БП_ЧерныйСписокКлиентов.Получить(Отбор);

Если ЗначениеЗаполнено(ЗначенияРесурсов.Причина) Тогда
    ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.ВЧерномСписке;
    ПричинаЧерныйСписок = ЗначенияРесурсов.Причина;
Иначе
    ЭлементыФормы.ПанельЧерныйСписок.ТекущаяСтраница = ЭлементыФормы.ПанельЧерныйСписок.Страницы.НеВЧерномСписке;
КонецЕсли;

Такой подход делает код чище, производительнее и проще в отладке.

← На главную