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