Как дать права на HTTP-сервис в расширении пользователю с ограниченными правами?

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

В процессе разработки часто возникает задача предоставить внешним системам доступ к данным через HTTP-сервисы. При этом важно соблюдать политику безопасности и не выдавать избыточных прав. Рассмотрим типичную ситуацию: вы создали HTTP-сервис в расширении, добавили для него специальную роль и назначили ее пользователю с правами «ТолькоПросмотр». Однако при попытке выполнить запрос к базе данных из этого сервиса, например, с помощью метода Запрос.Выполнить(), система возвращает ошибку доступа. При этом под пользователем с полными правами все работает корректно. Давайте разберемся, почему так происходит и как это исправить.

Анализ проблемы: почему прав на сам сервис недостаточно?

Ключевая особенность механизма безопасности платформы 1С заключается в том, что предоставление прав на объект метаданных (в нашем случае, на HTTP-сервис) не означает автоматического предоставления прав на данные, к которым этот объект обращается. Когда внешний запрос поступает на HTTP-сервис, платформа выполняет код этого сервиса в контексте указанного пользователя.

Это значит, что если в коде сервиса есть запрос к регистру сведений, справочнику или документу, система проверит, есть ли у пользователя, под которым выполняется запрос, право на чтение этих конкретных объектов. Стандартная роль «ТолькоПросмотр» имеет очень ограниченный набор разрешений, и в него могут не входить нужные вам таблицы.

Таким образом, ошибка на строке Запрос.Выполнить() — это классический симптом того, что у пользователя не хватает прав не на сам сервис, а на те данные, которые вы пытаетесь получить внутри него.

Решение 1: Быстрое решение через привилегированный режим

Самый быстрый способ решить проблему — временно отключить проверку прав для критического участка кода. Для этого в платформе 1С существует специальная процедура УстановитьПривилегированныйРежим().

Вызов УстановитьПривилегированныйРежим(Истина) запускает режим, в котором система перестает проверять права доступа к данным, включая ограничения на уровне записей (RLS). После выполнения кода, требующего полных прав, необходимо вернуть обычный режим вызовом УстановитьПривилегированныйРежим(Ложь).

Посмотрим на пример:


// Фрагмент кода в модуле HTTP-сервиса

// Включаем привилегированный режим перед выполнением запроса
УстановитьПривилегированныйРежим(Истина);

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

Исключение
    // Обязательно обрабатываем исключения, чтобы не оставить систему
    // в привилегированном режиме в случае ошибки.
    // Здесь можно логировать ошибку или вернуть соответствующий HTTP-статус.
    
КонецПопытки;

// Обязательно отключаем привилегированный режим после выполнения кода
УстановитьПривилегированныйРежим(Ложь);

Важные моменты при использовании привилегированного режима:

  1. Безопасность. Это мощный инструмент, который следует использовать с осторожностью. Если ваш сервис принимает параметры извне и использует их для построения запроса, возникает риск несанкционированного доступа к данным, так как RLS в этом режиме не работает. Всегда тщательно проверяйте и очищайте входящие параметры.
  2. Минимизация области действия. Включайте привилегированный режим только для минимально необходимого участка кода. Не стоит оборачивать в него всю процедуру обработчика запроса.
  3. Надежность. Всегда используйте конструкцию Попытка...Исключение, чтобы гарантировать вызов УстановитьПривилегированныйРежим(Ложь), даже если внутри блока произойдет ошибка.

Решение 2: Детальная настройка ролей

Более правильный и безопасный подход — не отключать проверку прав, а предоставить пользователю все необходимые разрешения. Этот путь требует больше времени на анализ, но делает систему более защищенной и предсказуемой.

Разберем по шагам, как это сделать:

  1. Находим недостающие права в Журнале регистрации (ЖР). Это самый эффективный способ диагностики. Откройте Журнал регистрации, установите фильтр по событию «Отказ в доступе» и по пользователю, под которым происходит ошибка. Попробуйте снова выполнить запрос к HTTP-сервису. В журнале появится запись, в которой будет точно указано, к какому объекту метаданных (например, Справочник.Контрагенты) и какого права (например, Чтение) не хватило.

  2. Редактируем роль. В конфигураторе найдите роль, которую вы создали для доступа к HTTP-сервису. Откройте ее.

  3. Выдаем права. На основании данных из ЖР найдите в дереве объектов метаданных нужные справочники, документы, регистры и установите для них флажок напротив права «Чтение» (или «Просмотр»).

  4. Проверяем связанные объекты. Часто упускаемый момент: если ваш запрос обращается, например, к регистру накопления, то помимо прав на сам регистр, могут потребоваться права на чтение его измерений (справочников, документов) и регистраторов. Если в ЖР вы видите отказ в доступе к объекту «Регистратор», значит, нужно дать права на чтение тех документов, которые делают движения по этому регистру.

Этот метод предпочтительнее, так как он соответствует принципу минимально необходимых привилегий и не создает потенциальных дыр в безопасности.

Дополнительно: Динамическое обращение к реквизитам объекта

В ходе обсуждения возник еще один интересный технический вопрос: как в модуле объекта (отчета или обработки) обратиться к его реквизиту, имя которого формируется динамически?

Например, у вас есть реквизиты ПутьКБазе_1, ПутьКБазе_2 и т.д., и в цикле нужно получить значение реквизита по его номеру.

В модуле формы это можно сделать через коллекцию элементов формы или реквизитов объекта, например: Отчет["ПутьКБазе" + НомерБазы]. А как быть в модуле самого объекта?

Для этого используется ключевое слово ЭтотОбъект. Оно предоставляет доступ к текущему экземпляру объекта обработки или отчета, и к его реквизитам можно обращаться через квадратные скобки, передавая имя реквизита в виде строки.

Пример кода для модуля объекта:


// Предположим, переменная НомерБазы содержит нужное число (1, 2, 3...)
НомерБазы = 1;

// Формируем имя реквизита динамически
ИмяРеквизита = "ПутьКБазе_" + Формат(НомерБазы, "ЧГ=0");

// Получаем значение реквизита, обращаясь к нему по имени
ЗначениеПути = ЭтотОбъект[ИмяРеквизита];

Сообщить("Путь к базе " + НомерБазы + ": " + ЗначениеПути);

Этот простой прием очень полезен при написании универсального кода, который должен работать с однотипными реквизитами.

← На главную