Как устроено ограничение доступа (RLS) в БСП и как перейти на производительный режим?

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

При разработке и сопровождении крупных информационных систем на платформе 1С:Предприятие 8 одним из наиболее критичных вопросов является производительность механизмов ограничения доступа на уровне записей (RLS — Record Level Security). В стандартных конфигурациях, построенных на базе 1С:Библиотеки стандартных подсистем (БСП), подсистема «Управление доступом» играет ключевую роль. Однако классическая реализация RLS часто приводит к существенному замедлению работы системы при росте объемов данных. Для комплексного анализа ролей, профилей и действующих настроек RLS подойдёт обработка для аудита прав доступа.

В этой статье мы подробно разберем, как устроена архитектура RLS в БСП, проанализируем разницу между классическим и производительным (универсальным) режимами, а также рассмотрим практические приемы оптимизации и программной подмены ограничений в формах динамических списков.

1. Классический RLS против Производительного режима в БСП

Для начала выясним причину, почему классический RLS называют неюзабельным на базах крупного размера, и как эту проблему решает универсальный производительный режим.

Классический (стандартный) режим RLS работает по принципу динамической модификации запросов СУБД непосредственно в момент обращения к базе данных. Платформа «на лету» перехватывает любой запрос пользователя к таблицам документов или справочников и добавляет к нему тяжелые соединения с регистрами сведений прав доступа (например, ТаблицыГруппДоступа, ЗначенияГруппДоступа). СУБД строит неоптимальные планы запросов, что выливается в критические зависания динамических списков, отчетов и журналов документов. В качестве альтернативного решения для ограничения видимости данных без тяжелых запросов RLS можно использовать инструмент для настройки отборов в отчетах и динамических списках.

Производительный (универсальный) режим ограничения доступа (внедренный в БСП начиная с версии 3.0) кардинально меняет логику работы системы. Рассмотрим подробнее ключевые аспекты этого механизма:

  1. Предварительный расчет прав. Вместо вычисления прав «на лету» при каждом чтении данных, права рассчитываются заранее — в момент записи объекта или при изменении настроек прав. Результаты расчетов сохраняются в плоские служебные таблицы — так называемые Ключи доступа (регистры сведений КлючиДоступаКОбъектам, КлючиДоступаКРегистрам и др.).
  2. Упрощение SQL-запросов. В роли конфигуратора закладывается специальный шаблон, использующий условную компиляцию:

#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
    #ДляОбъекта("")
#Иначе
    #ПоЗначениям(...)
#КонецЕсли

При включенном производительном режиме платформа подставляет простейший шаблон #ДляОбъекта(""). В результате СУБД выполняет элементарное и быстрое соединение таблицы объекта с предрассчитанной таблицей ключей доступа, что ускоряет выборку данных в десятки и сотни раз.

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

2. Как реализовать ограничение доступа в коде для разработчика

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

Разберем по шагам, что требуется сделать в коде для ограничения доступа (например, для нового документа по реквизиту Организация):

Шаг 1. Описание ограничений в модуле менеджера объекта. В модуле менеджера ограничиваемого справочника или документа необходимо объявить экспортную процедуру ПриЗаполненииОграниченияДоступа:


Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт
    
    Ограничение.Текст = 
    "РазрешитьЧтениеИзменение ГДЕ ЗначениеРазрешено(Организация)";
    
КонецПроцедуры

Если логика доступа сложнее и зависит от связанных таблиц, мы можем использовать метод ПрисоединитьДополнительныеТаблицы, связывая текущую таблицу с другими объектами метаданных.

Шаг 2. Интеграция с формами. Чтобы система корректно отрабатывала проверку прав при интерактивных действиях пользователя, в модулях форм объектов (документов или справочников) необходимо прописать стандартные вызовы БСП:


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    // СтандартныеПодсистемы.УправлениеДоступом
    УправлениеДоступом.ПриЧтенииНаСервере(ЭтотОбъект, ТекущийОбъект);
    // Конец СтандартныеПодсистемы.УправлениеДоступом
КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
    // СтандартныеПодсистемы.УправлениеДоступом
    УправлениеДоступом.ПослеЗаписиНаСервере(ЭтотОбъект, ТекущийОбъект, ПараметрыЗаписи);
    // Конец СтандартныеПодсистемы.УправлениеДоступом
КонецПроцедуры

3. Оптимизация и замена «ПоНаборамЗначений» в формах списков

Шаблон RLS #ПоНаборамЗначений применяется для объектов со сложной многоуровневой логикой (например, когда доступ предоставляется по условию «И» или «ИЛИ» для нескольких аналитик одновременно). Для его работы объект должен содержать табличную часть НаборыЗначенийДоступа. В формах списков этот шаблон традиционно вызывает серьезные проблемы с производительностью. Проанализируем, как можно оптимизировать или подменить этот механизм.

Вариант А. Переход на универсальный режим RLS

Это наиболее предпочтительный и штатный способ оптимизации. При активации константы ОграничиватьДоступНаУровнеЗаписейУниверсально система физически перестает связывать динамические списки с табличной частью НаборыЗначенийДоступа при чтении. Вместо этого в динамическом списке отрабатывает быстрый шаблон #ДляОбъекта(""), ссылающийся на плоскую таблицу рассчитанных ключей доступа. Сама табличная часть документа по-прежнему заполняется при записи объекта, но используется СУБД исключительно для фонового расчета ключей.

Вариант Б. Программная подмена RLS через отборы динамического списка

Если информационная база вынуждена работать в стандартном (не производительном) режиме, использование #ПоНаборамЗначений в динамических списках можно обойти с помощью штатного механизма БСП по замене неявных RLS-запросов на явные параметры. Выясним, как это работает:

  1. В обработчике ПриСозданииНаСервере формы списка вызывается программная настройка отборов:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    ОписаниеОтборов = Новый Структура;
    ОписаниеОтборов.Вставить("Организация", "Организация");
    
    УправлениеДоступом.НастроитьОтборыДинамическогоСписка(Список, ОписаниеОтборов);
    
КонецПроцедуры
  1. Метод НастроитьОтборыДинамическогоСписка обращается к функции РазрешенныеЗначенияДляДинамическогоСписка и получает плоский массив доступных текущему пользователю элементов (например, список разрешенных организаций).
  2. Если количество разрешенных объектов относительно невелико (как правило, до 100 элементов), БСП «на лету» модифицирует текст запроса динамического списка, принудительно внедряя в секцию ГДЕ условие вида: ОсновнаяТаблица.Организация В (&РазрешенныеОрганизации).
  3. Для СУБД такой прямой параметризованный запрос отрабатывает в разы быстрее, полностью исключая необходимость обращения к тяжелым таблицам RLS.

Вариант В. Ручная кастомизация динамического списка

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

← На главную