При разработке самописных конфигураций на платформе 1С часто возникает задача: ограничить видимость и редактирование документов таким образом, чтобы сотрудники работали только со своими участками, подразделениями или филиалами. При этом отбор должен применяться автоматически при входе в систему без необходимости ручной настройки со стороны пользователя.
Разберем детально, как правильно выстроить архитектуру связки пользователей с участками и реализовать разграничение прав доступа в базе данных.
Главная сложность, с которой сталкиваются разработчики при создании ограничений, заключается в том, что системный объект платформы ПользовательИнформационнойБазы не является объектом метаданных конфигурации. На него нельзя создать прямую ссылку в измерениях регистров или реквизитах документов.
Поэтому в конфигурациях (включая типовые решения на базе БСП) применяется классическая схема:
Пользователи, элементы которого сопоставляются с системными учетными записями.ПараметрыСеанса при запуске программы.Создадим справочник Пользователи. Добавим в него реквизит ИдентификаторПользователяИБ с типом УникальныйИдентификатор. Также в справочнике можно предусмотреть реквизит ОсновнойУчасток со ссылкой на справочник Участки для автоматической подстановки значения по умолчанию при создании новых документов.
При начале сеанса в модуле сеанса связываем текущую системную учетную запись с элементом нашего справочника. Для этого используем метод ПользователиИнформационнойБазы.ТекущийПользователь() и получаем его уникальный идентификатор:
УникальныйИдентификатор = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
СсылкаНаПользователя = Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ", УникальныйИдентификатор);
Так как одному пользователю может быть разрешен доступ сразу к нескольким участкам, для хранения прав создадим непериодический регистр сведений ДоступПользователейКУчасткам со следующей структурой:
Пользователь (Тип: СправочникСсылка.Пользователи, Ведущее: Истина).Участок (Тип: СправочникСсылка.Участки, Ведущее: Истина).Такая структура позволяет гибко назначать каждому сотруднику произвольный список разрешенных участков через интерфейс управления правами.
Чтобы не выполнять тяжелые запросы к регистру сведений при каждом открытии формы или проверке прав, сохраним доступные участки в параметрах сеанса. Создадим параметры сеанса ТекущийПользователь (тип: СправочникСсылка.Пользователи) и ДоступныеУчастки (тип: ФиксированныйМассив).
В модуле сеанса в процедуре УстановкаПараметровСеанса заполняем эти параметры:
Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
Если ТребуемыеПараметры.Найти("ТекущийПользователь") <> Неопределено
Или ТребуемыеПараметры.Найти("ДоступныеУчастки") <> Неопределено Тогда
Идентификатор = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
ТекущийПользовательСсылка = Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ", Идентификатор);
ПараметрыСеанса.ТекущийПользователь = ТекущийПользовательСсылка;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДоступПользователейКУчасткам.Участок КАК Участок
|ИЗ
| РегистрСведений.ДоступПользователейКУчасткам КАК ДоступПользователейКУчасткам
|ГДЕ
| ДоступПользователейКУчасткам.Пользователь = &ТекущийПользователь";
Запрос.УстановитьПараметр("ТекущийПользователь", ТекущийПользовательСсылка);
МассивУчастков = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Участок");
ПараметрыСеанса.ДоступныеУчастки = Новый ФиксированныйМассив(МассивУчастков);
КонецЕсли;
КонецПроцедуры
Для гарантированной защиты данных от несанкционированного просмотра и изменения настроим ограничение доступа на уровне записей (RLS) в ролях пользователей.
В правах роли для нужных документов на операцию Чтение прописываем условие ограничения доступа. Сравнение реквизита документа Участок с параметром сеанса выглядит следующим образом:
ГДЕ Участок В (&ДоступныеУчастки)
Важно: для полноценного контроля аналогичное условие необходимо продублировать на права Добавление и Изменение, чтобы пользователи не могли вручную или программно записать документ с чужим участком.
Следует учитывать, что механизм RLS создает дополнительную нагрузку на СУБД при формировании запросов. Использование заранее подготовленного параметра сеанса &ДоступныеУчастки сводит эту нагрузку к минимуму, так как исключает необходимость выполнения подзапросов к регистру сведений при каждом чтении данных.
Если в конфигурации требуется только комфортная работа пользователей без строгого ограничения прав на уровне СУБД, фильтрацию можно реализовать через динамические списки в формах.
В процедуре ПриСозданииНаСервере формы списка документов устанавливаем отбор:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЭлементОтбора = Список.ФиксированныеНастройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Участок");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = ПараметрыСеанса.ДоступныеУчастки;
ЭлементОтбора.Использование = Истина;
КонецПроцедуры
А для автоматического заполнения реквизита Участок при создании новых документов используем процедуру ОбработкаЗаполнения в модуле объекта документа:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
Если Не ЗначениеЗаполнено(Участок) Тогда
Участок = ПараметрыСеанса.ТекущийПользователь.ОсновнойУчасток;
КонецЕсли;
КонецПроцедуры
Обратите внимание: интерфейсный отбор в динамических списках скрывает документы только в конкретной форме, но не блокирует доступ к ним через отчеты, консоли запросов или внешние обработки. Для обеспечения безопасности данных всегда комбинируйте интерфейсные настройки с RLS или проверками в подписке на событие ПередЗаписью.