RLS в БСП в производительном варианте настраивается не в ролях, а в модуле менеджера объекта: вы описываете текст ограничения в процедуре ПриЗаполненииОграниченияДоступа, регистрируете объект в УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа, добавляете его в определяемые типы владельцев ключей доступа и ставите в ролях короткий шаблон #ДляОбъекта или #ДляРегистра. После этого подсистема «Управление доступом» рассчитывает ключи доступа и проверяет права через них.

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

Как устроен производительный вариант RLS

Включается он настройкой «Ограничивать доступ на уровне записей» с универсальным режимом. Отличие от классического варианта:

Классический RLSПроизводительный (универсальный)
Где описано ограничениеДлинные шаблоны в каждой ролиТекст в модуле менеджера объекта
Как проверяетсяУсловие с подзапросами к значениям доступаЧерез рассчитанные ключи доступа
Шаблон в ролиПараметризованный под объектУнифицированный ДляОбъекта / ДляРегистра
ПоддержкаПравки во многих роляхПравка в одном месте

Язык ограничения — подмножество языка запросов с собственными конструкциями: РазрешитьЧтениеИзменение, ГДЕ, ЗначениеРазрешено(), ПрисоединитьДополнительныеТаблицы и другими. Полное описание — в комментарии к ПриЗаполненииСписковСОграничениемДоступа в общем модуле УправлениеДоступомПереопределяемый вашей версии БСП. Я всегда открываю его перед работой: синтаксис расширялся от версии к версии.

RLS в БСП: каждой записи сопоставлен ключ доступа, и пользователь видит только записи с разрешёнными ключами
RLS в БСП: каждой записи сопоставлен ключ доступа, и пользователь видит только записи с разрешёнными ключами

Подключение справочника или документа

Шаг 1. Текст ограничения в модуле менеджера

Простой случай — значение доступа лежит в реквизите самого объекта:

1С
// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа.
Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт

	Ограничение.Текст =
	"РазрешитьЧтениеИзменение
	|ГДЕ
	|	ЗначениеРазрешено(Организация)";

КонецПроцедуры

Если нужное значение не в самом объекте, а в реквизите связанного объекта (например, организация — это владелец подразделения), присоединяем таблицу:

1С
// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа.
Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт

	Ограничение.Текст =
	"ПрисоединитьДополнительныеТаблицы
	|ЭтотСписок КАК Т
	|ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ПодразделенияОрганизаций КАК Подразделения
	|	ПО Подразделения.Ссылка = Т.Подразделение
	|;
	|РазрешитьЧтениеИзменение
	|ГДЕ
	|	ЗначениеРазрешено(Подразделения.Владелец)";

КонецПроцедуры

Когда стоит завести отдельный реквизит

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

1С
Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт

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

КонецПроцедуры

Не забудьте заполнить реквизит у уже существующих объектов обработчиком обновления — иначе старые данные окажутся с пустым значением доступа.

Шаг 2. Форма объекта

В модуль формы объекта добавляются вызовы подсистемы — они нужны, чтобы форма корректно отрабатывала режим «только просмотр» и пересчёт ключей после записи:

1С
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)

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

КонецПроцедуры

&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)

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

КонецПроцедуры

Шаг 3. Определяемые типы

Добавьте тип ссылки объекта в определяемый тип ВладелецЗначенийКлючейДоступа. Для документов дополнительно — в ВладелецЗначенийКлючейДоступаДокумент. Без этого подсистема не сможет хранить ключи доступа объекта.

Шаг 4. Регистрация списка

1С
// УправлениеДоступомПереопределяемый
Процедура ПриЗаполненииСписковСОграничениемДоступа(Списки) Экспорт

	// ... типовые строки
	Списки.Вставить(Метаданные.Справочники.ДоговорыПодряда, Истина);
	Списки.Вставить(Метаданные.Документы.АктВыполненныхРабот, Истина);

КонецПроцедуры

Значение Истина означает, что ограничение описано в модуле менеджера объекта.

Шаг 5. Шаблон в ролях

Во все роли, которые дают право чтения (и изменения) объекта, добавьте ограничение:

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

Сам шаблон ДляОбъекта в новые роли проще всего скопировать из любой типовой роли, где он уже есть, — например, из роли изменения участников групп доступа. Так вы гарантированно получите правильный текст шаблона вашей версии БСП.

Подключение регистра сведений без регистратора

Для независимого регистра сведений шаги похожи, но с отличиями.

  1. Добавьте тип набора записей в определяемый тип ВладелецЗначенийКлючейДоступаНаборЗаписей.
  2. Зарегистрируйте регистр в ПриЗаполненииСписковСОграничениемДоступа.
  3. Опишите ограничение в модуле менеджера регистра. Если значение доступа — реквизит документа, на который ссылается измерение:
1С
// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа.
Процедура ПриЗаполненииОграниченияДоступа(Ограничение) Экспорт

	Ограничение.Текст =
	"ПрисоединитьДополнительныеТаблицы
	|ЭтотСписок КАК Т
	|ЛЕВОЕ СОЕДИНЕНИЕ Документ.ЗаказПоставщику КАК Заказы
	|	ПО Заказы.Ссылка = Т.ЗаказПоставщику
	|;
	|РазрешитьЧтениеИзменение
	|ГДЕ
	|	ЗначениеРазрешено(Заказы.Подразделение)";

КонецПроцедуры
  1. Если шаблон регистра ссылается на идентификатор объекта метаданных, добавьте предопределённый элемент в справочник ИдентификаторыОбъектовМетаданных по правилу «РегистрСведений» + имя регистра.
  2. В роли — шаблон ДляРегистра, где первым параметром указан этот идентификатор, вторым — поле регистра, по которому строится ограничение:
1С
#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
#ДляРегистра("ИдентификаторыОбъектовМетаданных.РегистрСведенийСостояниеОбеспечения", "ЗаказПоставщику", "", "", "", "")
#Иначе
Истина
#КонецЕсли

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

Проверка ограничения после подключения

Прежде чем отдавать изменения пользователям, я проверяю ограничение по короткому сценарию:

  1. Тестовый пользователь. Заведите пользователя с одной группой доступа, где разрешена одна организация (или одно подразделение — по тому виду доступа, который вы настраиваете).
  2. Данные с разными значениями доступа. Нужны объекты как минимум двух организаций и, отдельно, объект с пустым значением.
  3. Список. Откройте список объекта под тестовым пользователем: должны быть видны только разрешённые записи, без ошибок «Недостаточно прав».
  4. Ссылочные поля. Откройте документ, который ссылается на запрещённый объект: вместо представления должно быть «Объект не найден» или аналогичное, но форма должна открываться.
  5. Отчёты. Сформируйте отчёт по объекту: строки с запрещёнными значениями не должны попадать в результат.
  6. Запись. Попробуйте изменить запрещённый объект, если право изменения ограничено, — запись должна быть отклонена.

Этот сценарий занимает полчаса, а ловит большую часть ошибок: забытую роль, неверное поле в ЗначениеРазрешено, отсутствие обновления служебных данных.

Обновление служебных данных

После изменения конфигурации подсистема должна пересчитать параметры ограничения и ключи доступа. Варианты:

  • выпустить изменение с увеличением номера версии конфигурации — пересчёт пройдёт при обновлении ИБ;
  • запустить обновление информационной базы вручную (параметр запуска для принудительного обновления ИБ, предусмотренный в БСП);
  • воспользоваться служебной обработкой обновления вспомогательных данных, если она есть в вашей поставке.

Пока данные не пересчитаны, поведение RLS может не соответствовать новым настройкам.

Пользователь видит лишние данные: чек-лист

Если при включённом RLS пользователь видит объекты, которых видеть не должен, проверяю по порядку:

  1. Группы доступа пользователя. Одна группа с профилем без ограничения по нужному виду доступа (или с «Все разрешены») открывает всё. Это организационная ошибка — решается с ответственным за права. Смотрите отчёт о правах доступа пользователя.
  2. Роли без шаблона. Если хотя бы в одной роли пользователя у объекта стоит право чтения без ограничения, RLS для него не работает. Служебный регистр сведений ПраваРолей показывает, есть ли у роли право без ограничений: для ограниченных ролей там должно быть «нет». Если стоит «да» — добавьте шаблон.
  3. Устаревшие служебные регистры. Шаблон добавлен, а ПраваРолей или ТаблицыГруппДоступа показывают старое состояние — служебные данные не обновились. Выполните обновление ИБ.
  4. Значение доступа пустое. Объекты с пустым значением в поле ограничения могут быть разрешены или запрещены в зависимости от настроек вида доступа — проверьте заполнение.

На практике первые три пункта закрывают почти все случаи «лишней видимости».

RLS ломается не в тексте ограничения, а в мелочах: забытая роль, необновлённые регистры, группа доступа «на всякий случай».

Подключение своих объектов к управлению доступом делаю в рамках доработки 1С; если права в базе давно настраивались разными людьми и непонятно, кто что видит, начинаем с аудита 1С.

Итог

  • Ограничение описывается в ПриЗаполненииОграниченияДоступа модуля менеджера, объект регистрируется в ПриЗаполненииСписковСОграничениемДоступа.
  • Тип объекта добавляется в определяемые типы ВладелецЗначенийКлючейДоступа*, в форму — вызовы УправлениеДоступом.
  • В роли ставится шаблон ДляОбъекта или ДляРегистра, проще всего скопировать его из типовой роли.
  • Для составных полей заводите отдельный реквизит доступа и заполняйте его перед записью.
  • Лишняя видимость — это почти всегда группы доступа, роль без шаблона или необновлённые служебные регистры.