При интеграции сторонних систем с 1С через стандартный интерфейс OData разработчики часто сталкиваются с ситуацией, когда включение ограничений доступа на уровне записей (RLS) полностью ломает получение данных. Например, в конфигурации 1С:ERP Управление предприятием при настройке профилей безопасности с ограничением хотя бы по одной организации стандартный OData-запрос к справочнику организаций или документам возвращает ошибку «Доступ. Отказ в доступе» (HTTP-код 401 или 403). Проанализируем причину такого поведения платформы и разберем способы получения разрешенных данных.
В обычном коде конфигурации при выполнении запроса к таблицам с ограничениями RLS платформа требует явного указания конструкции ВЫБРАТЬ РАЗРЕШЕННЫЕ. Если этого ключевого слова в запросе нет, а в выборку попадает хотя бы одна строка, на которую у текущего пользователя нет прав, платформа генерирует исключение нарушения прав доступа вместо того, чтобы просто отсечь запрещенную запись.
Стандартный интерфейс OData платформы 1С:Предприятие работает точно так же: по умолчанию он формирует внутренний запрос без директивы чтения только разрешенных записей. В результате, обращаясь к коллекции объектов, интеграционный пользователь пытается прочитать всю таблицу целиком, натыкается на RLS-ограничение и получает ошибку отказа в доступе.
Для реализации поведения, аналогичного директиве ВЫБРАТЬ РАЗРЕШЕННЫЕ, в стандартном интерфейсе OData предусмотрен специальный параметр URL-запроса — allowedOnly=true. Добавив этот параметр к строке вызова, мы заставляем платформу выбирать только те данные, к которым у пользователя есть действующие права.
Посмотрим на пример формирования строки запроса:
http://server/base/odata/standard.odata/Catalog_Организации?$format=json&allowedOnly=true
При передаче allowedOnly=true платформа формирует внутренний запрос с отбором доступных записей, и ответ возвращает корректный список организаций без ошибки доступа.
Рассмотрим технические тонкости, с которыми можно столкнуться при использовании данного параметра в рабочей базе:
allowedOnly=true действует исключительно при получении наборов данных (коллекций). Если внешняя система обращается к конкретной записи напрямую по ее уникальному идентификатору GUID (например, Catalog_Организации(guid'...')), и на эту запись у пользователя нет прав по RLS, параметр не спасет — платформа гарантированно вернет ошибку отказа в доступе.$expand, а внутри связанной таблицы оказывается объект, заблокированный правами доступа, запрос может завершиться ошибкой, даже несмотря на наличие флага allowedOnly=true.allowedOnly=true совместно с постраничной навигацией (параметры $top, $skip) и подсчетом количества строк ($inlinecount или $count) создает высокую нагрузку на СУБД. Платформе приходится предварительно рассчитывать условия ограничений для всего массива записей, чтобы корректно определить смещение.В конфигурации 1С:ERP обычно включен производительный вариант работы RLS, построенный на механизме ключей доступа подсистемы БСП. Разберем особенности его взаимодействия с OData:
Если штатный OData-интерфейс с параметром allowedOnly=true не закрывает потребности проекта из-за ограничений производительности или проблем со связанными сущностями, рассмотрим альтернативные варианты интеграции:
Создание собственного HTTP-сервиса в конфигурации или расширении позволяет гибко управлять логикой чтения. В коде обработчика запроса можно написать оптимальный текст запроса с ВЫБРАТЬ РАЗРЕШЕННЫЕ либо использовать привилегированный режим, отдавая внешнему клиенту сформированный JSON:
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Организации.Ссылка КАК Ссылка,
| Организации.Наименование КАК Наименование
|ИЗ
| Справочник.Организации КАК Организации";
Результат = Запрос.Выполнить().Выгрузить();
Для интеграционного обмена заводится отдельная учетная запись без ограничений по RLS (с полными правами только на чтение необходимых справочников и документов). Фильтрация данных по конкретной организации в этом случае переносится на сторону внешнего сервиса с помощью стандартного фильтра OData:
?$filter=Организация_Key eq guid'00000000-0000-0000-0000-000000000000'
Такой подход полностью исключает накладные расходы механизмов RLS на стороне СУБД и предотвращает неожиданные отказы в доступе при выборке коллекций.