1c-rls-perf-connect · git:20261025.d15943f · 2026-10-25 · sha256 f3ebeca6011a2f43
1c-rls-perf-connect git:20261025.d15943fA
Immutable. This exact content never changes and is served at /api/v1/blob/f3ebeca6011a2f43.
---
name: 1c-rls-perf-connect
description: "Подключение нового объекта (документа, справочника, регистра сведений), в том числе из расширения, к ограничению доступа на уровне записей БСП в производительном варианте. Применять когда просят ограничить видимость по складу, организации, подразделению через управление доступом; когда динамический список падает с Ошибка создания набора данных НаборДанныхДинамическогоСписка; когда обновление доступа падает с Не указана логическая операция или Преобразование значения к типу Булево; когда журнал документов показывает записи, скрытые ограничением."
---
# Подключение объекта к производительному RLS БСП
Производительный вариант ограничения доступа не разворачивает условие роли напрямую, а строит
предрассчитанные ключи доступа в регистрах `КлючиДоступаКОбъектам` и `КлючиДоступаКРегистрам`.
Текста ограничения недостаточно: объект должен входить в служебные структуры подсистемы, иначе
список не открывается.
Вариант работы: НСИ и администрирование - Настройки пользователей и прав - Группы доступа - Вариант
работы; программно - `УправлениеДоступом.ПроизводительныйВариант()`. Вариант выбирает активную ветку
условия роли и сам по себе причиной падения списков не бывает. Шаги ниже выполняются и в стандартном
варианте: без них условие роли перестает разворачиваться после переключения варианта.
Смежные справочники набора:
| Вопрос | Где |
|---|---|
| программный интерфейс `УправлениеДоступом`, наборы значений доступа, пересчет прав | скил `1c-ssl-patterns`, `references/access-management.md` |
| сигнатура и существование метода БСП | скил `1c-bsp-api` |
| профили групп доступа из кода, `ЧтениеРазрешено`, `ЕстьРоль` | правило `bsp-profile-rights-api.md` |
| роль с условием и шаблонами в формате Конфигуратора | скилы `1c-role-compile`, `1c-role-edit`, `1c-role-validate` |
## Когда НЕ применять
- Ограничение делается отбором в форме, а не подсистемой доступа.
- Конфигурация без БСП или без подсистемы Управление доступом.
- Нужно раздать роли и права целиком, без ограничения по значениям: это профили групп доступа, не RLS.
## Шаги
Роли и определяемые типы должны быть готовы до первого обновления доступа.
В EDT-проекте метаданные и модули правятся инструментами сервера `ai-edt` (каталог - скил
`ai-edt-tools`): BSL через `write_module_source`, метаданные через `edit_metadata`, перед
`update_database` - `validate_for_export`. В формате Конфигуратора - скилы `1c-cfe-*`, `1c-meta-*`,
`1c-role-*`.
### 1. Зарегистрировать список
В `УправлениеДоступомПереопределяемый` (в расширении - перехват `&После`, скил `1c-cfe-patch-method`):
- `ПриЗаполненииСписковСОграничениемДоступа(Списки)` - `Списки.Вставить(Метаданные.<Тип>.<Имя>, Истина)`.
- `ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(Описание)` - строки вида
`Документ.ЗаказКлиента.Чтение.Склады` и `Документ.ЗаказКлиента.Изменение.Склады`.
Готово когда: каждый подключаемый объект присутствует в обеих процедурах.
### 2. Текст ограничения в модуле менеджера
Экспортная `ПриЗаполненииОграниченияДоступа(Ограничение)`, поле `Ограничение.Текст`.
**Оператор `ССЫЛКА` язык ограничений доступа не разбирает.** Обновление доступа завершается ошибкой
"Не указана логическая операция" с указанием на выражение с `ССЫЛКА`. Проверка типа составного поля
пишется через `ТИПЗНАЧЕНИЯ(Поле) = ТИП(Документ.ЗаказКлиента)`, отрицание - `<>`. Эталон: модуль
менеджера `РегистрСведений.ДатыЗапретаИзменения` в типовой конфигурации.
Поле не в самом объекте, а в связанном - `ПрисоединитьДополнительныеТаблицы` либо `ВЫРАЗИТЬ` по
типу. При составном поле каждая ветка сначала отсекает тип и только потом проверяет значение:
`ВЫРАЗИТЬ` к неподходящему типу возвращает пустую ссылку, и запись другого типа проходит через ветку
"значение не заполнено".
Готово когда: текст написан, проверки типов записаны через `ТИПЗНАЧЕНИЯ`, без `ССЫЛКА`.
### 3. Определяемые типы
Объект, не внесенный в определяемые типы, дает падение списка при правильном тексте ограничения.
| Определяемый тип | Что добавить |
|---|---|
| `ВладелецЗначенийКлючейДоступа` | ссылочный тип объекта (`DocumentRef.ЗаказКлиента`, `CatalogRef.Контрагенты`) |
| `ВладелецЗначенийКлючейДоступаДокумент` | `DocumentObject.ЗаказКлиента` - только для документов |
| `ВладелецЗначенийКлючейДоступаНаборЗаписей` | `InformationRegisterRecordSet.<Имя>` - для регистров |
| `ПолеРегистраКлючейДоступаКРегистрам` | типы полей регистра, по которым идет ограничение |
Шаблон роли соединяет список с регистром ключей условием
`КлючиДоступаКОбъектам.Объект = ТекущаяТаблица.Ссылка`, а измерение `Объект` имеет тип
`DefinedType.ВладелецЗначенийКлючейДоступа`. Типа объекта в составе нет - сравниваются несовместимые
типы, запрос списка не собирается.
Из расширения определяемый тип заимствуется и расширяется блоком `typeExtension` с
`<state>Extended</state>` (проверено на платформе 8.3.27).
Типовые объекты в `ВладелецЗначенийКлючейДоступа` берутся из состава этого типа в релизе поставщика,
а не выводятся из кода: наличие `ПриЗаполненииОграниченияДоступа` в модуле менеджера не означает, что
объект - владелец ключей, а объекты из `ПриЗаполненииСписковСОграничениемДоступа` такого обработчика
могут не иметь. Добавляются объекты, которые есть и в составе релиза, и в конфигурации. Если состав
типа отстает от релиза, обновление доступа завершается ошибкой "Преобразование значения к типу Булево
не может быть выполнено" в `УправлениеДоступомСлужебный`. EDT-валидация эту ошибку не показывает.
Готово когда: каждый подключаемый объект и каждый тип его ограничивающего поля присутствуют в
соответствующих определяемых типах.
### 4. Идентификатор для регистров
Регистру нужен предопределенный элемент справочника идентификаторов с именем
`РегистрСведений<ИмяРегистра>`: для объектов расширения - в `ИдентификаторыОбъектовРасширений`, для
основной конфигурации - в `ИдентификаторыОбъектовМетаданных`. Измерение
`КлючиДоступаКРегистрам.Регистр` принимает ссылки обоих справочников, выбор определяется
принадлежностью регистра.
Готово когда: предопределенный элемент существует и его имя совпадает с первым параметром
`#ДляРегистра` в ролях.
### 5. Роли: условие и тело шаблона
Условие на праве (`restrictionByCondition` в EDT):
```
#Если &ОграничениеДоступаНаУровнеЗаписейУниверсально #Тогда
#ДляОбъекта("")
#Иначе
#ПоЗначениям( "Документ.ЗаказКлиента","Чтение","", "Склады","Склад", ... )
#КонецЕсли
```
Для регистров вместо `#ДляОбъекта` - `#ДляРегистра("ИдентификаторыОбъектовРасширений.РегистрСведений<Имя>",
"ПолеОтбора", "", "", "", "")`. Число пар параметров в `#ПоЗначениям` берется по типовой роли.
**Шаблон ограничения - свойство каждой роли, а не общий объект конфигурации.** Вызов `#ДляОбъекта(...)`
без определения шаблона в этой же роли не разворачивается, и динамический список падает с "Ошибка
создания набора данных" на всех подключенных объектах сразу. В EDT шаблон - блок
`<restrictionTemplate>` в `Rights.rights` роли.
Тела шаблонов копируются из типовых ролей без изменений: `ДляОбъекта(ПолеОбъекта)` и `ПоЗначениям`
есть в любой типовой роли с ограничением по значениям, `ДляРегистра(Регистр, Поле1..Поле5)` - в
типовой роли, ограничивающей регистр сведений. Тексты шаблонов одинаковы во всех ролях; совпадение
проверяется хешем текста.
Роли документа нужны `ДляОбъекта` и `ПоЗначениям`, роли регистра - `ДляРегистра` и `ПоЗначениям`.
`ПоЗначениям` добавляется и в производительном варианте: это ветка стандартного варианта.
Готово когда: в каждой роли с `restrictionByCondition` определены все шаблоны, которые вызывает ее
условие.
### 6. Формы объекта
В модуль формы объекта:
```bsl
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
УправлениеДоступом.ПриЧтенииНаСервере(ЭтотОбъект, ТекущийОбъект);
КонецПроцедуры
&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)
УправлениеДоступом.ПослеЗаписиНаСервере(ЭтотОбъект, ТекущийОбъект, ПараметрыЗаписи);
КонецПроцедуры
```
Без них изменение значения доступа (склада) при интерактивной записи не отражается в ключах доступа
до планового обновления. На открытие списков не влияет.
Готово когда: обработчики есть в форме объекта каждого подключенного документа и справочника.
### 7. Перестроить вспомогательные данные
БСП перезаполняет регистры `ПраваРолей` и `ТаблицыГруппДоступа` только при смене версии конфигурации
или расширения. При прежней версии регистры не получают записей по новым спискам, и ключи доступа не
строятся.
Способ - поднять версию расширения (или конфигурации): обновление выполняется штатным механизмом
БСП, порциями, фоновым заданием.
Синхронные служебные вызовы `РегистрыСведений.ПраваРолей.ОбновитьДанныеРегистра`,
`РегистрыСведений.ТаблицыГруппДоступа.ОбновитьДанныеРегистра` и
`УправлениеДоступомСлужебный.ОбновитьВспомогательныеДанныеПоИзменениямКонфигурации` строят данные по
всем спискам конфигурации в одном сеансе; на крупной конфигурации их последовательный запуск в одном
сеансе завершился аварийным завершением платформы. Запасной вариант - запускать по одному.
Готово когда: версия поднята, база обновлена, обновление доступа на уровне записей завершено.
### 8. Настройка в Предприятии
Профиль групп доступа с видом доступа (Склады) и значением "Все запрещены, исключения назначаются в
группах доступа". Затем группа доступа на каждое значение: участники и разрешенное значение. После
изменений - Настройки пользователей и прав - Обновление доступа на уровне записей - Запустить сейчас,
дождаться 100 процентов. До окончания построения ключей подключенные списки пустые.
Готово когда: под тестовым пользователем список открывается и показывает только разрешенные записи.
## Журналы документов
На платформе 8.3.27 ограничение чтения журнала документов перестает действовать, если у сеанса нет
права Чтение хотя бы на один вид документов, зарегистрированный в журнале. В SQL запроса к журналу
появляется ветка `_DocumentTRef IN (<читаемые виды>)` без условия роли: `(K AND C) OR K`, `K OR K OR C`
или `K OR K AND C` в зависимости от вида запроса, где `K` - отбор по читаемым видам, `C` - условие
ограничения. Журнал показывает строки читаемых видов без ограничения, при `K OR K OR C` - и строки
нечитаемого вида. Сами документы при этом ограничиваются, открытие чужого документа из журнала дает
"Недостаточно прав".
SQL одинаков для условия в роли и для шаблона ограничения роли. Поведение воспроизводится в
конфигурации без БСП: ветку добавляет платформа, а не шаблон `ДляОбъекта`.
Что делать: профиль, которому выдан журнал, должен читать все виды документов журнала. Новый документ,
добавленный в типовой журнал, требует права Чтение в каждом профиле, читающем этот журнал. Проверка -
`ВЫБРАТЬ РАЗРЕШЕННЫЕ` к журналу под пользователем профиля (скил `1c-mcp-toolkit`, `execute_query`
после `validate_query`): число строк журнала по виду не больше числа строк того же документа.
## Диагностика по симптому
| Симптом | Причина |
|---|---|
| Все подключенные списки падают "Ошибка создания набора данных НаборДанныхДинамическогоСписка" | нет тел шаблонов в ролях (шаг 5) либо объект не в определяемых типах (шаг 3) |
| Обновление доступа: "Не указана логическая операция" с указанием на `ССЫЛКА` | оператор `ССЫЛКА` в тексте ограничения (шаг 2) |
| Обновление доступа: "Преобразование значения к типу Булево не может быть выполнено" | состав `ВладелецЗначенийКлючейДоступа` отстает от релиза (шаг 3) |
| Списки открываются, но пустые | ключи еще строятся: Обновление доступа на уровне записей |
| Списки показывают записи с чужим значением | ветка условия не отсекает тип перед `ВЫРАЗИТЬ` (шаг 2) |
| Ключи не строятся после обновления конфигурации | версия конфигурации или расширения не поднята (шаг 7) |
| Аварийное завершение при перестроении данных | синхронные служебные вызовы вместо поднятия версии (шаг 7) |
| Журнал документов показывает строки, скрытые в списке документа | профиль не читает один из видов документов журнала (раздел "Журналы документов") |
## Проверка результата
Собранный `.cfe` проверяется по содержимому: распаковать скилом `v8unpack-cf`
(`python -m v8unpack -E "<файл.cfe>" <папка>`) и искать по дереву. Состав определяемого типа хранится в
`DefinedType.json` в виде UUID типов, а не имен - сверять с `refType typeId` в `.mdo` объекта.
Видимость под пользователем - запросом `ВЫБРАТЬ РАЗРЕШЕННЫЕ` в живой базе через `1c-mcp-toolkit`.