Как настроить разграничение доступа и фильтрацию документов по участкам для пользователей в 1С?

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

При разработке самописных конфигураций на платформе 1С часто возникает задача: ограничить видимость и редактирование документов таким образом, чтобы сотрудники работали только со своими участками, подразделениями или филиалами. При этом отбор должен применяться автоматически при входе в систему без необходимости ручной настройки со стороны пользователя.

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

Архитектурная концепция: почему системных пользователей недостаточно

Главная сложность, с которой сталкиваются разработчики при создании ограничений, заключается в том, что системный объект платформы ПользовательИнформационнойБазы не является объектом метаданных конфигурации. На него нельзя создать прямую ссылку в измерениях регистров или реквизитах документов.

Поэтому в конфигурациях (включая типовые решения на базе БСП) применяется классическая схема:

  1. Создается прикладной справочник Пользователи, элементы которого сопоставляются с системными учетными записями.
  2. Создается независимый непериодический регистр сведений для связи «многие-ко-многим» между пользователями и участками.
  3. Текущие настройки пользователя и доступные ему участки кэшируются в ПараметрыСеанса при запуске программы.
  4. На уровне прав настраивается механизм RLS (ограничение доступа на уровне записей) либо программный интерфейсный отбор в формах.

Шаг 1. Создание прикладного справочника и связывание с пользователем ИБ

Создадим справочник Пользователи. Добавим в него реквизит ИдентификаторПользователяИБ с типом УникальныйИдентификатор. Также в справочнике можно предусмотреть реквизит ОсновнойУчасток со ссылкой на справочник Участки для автоматической подстановки значения по умолчанию при создании новых документов.

При начале сеанса в модуле сеанса связываем текущую системную учетную запись с элементом нашего справочника. Для этого используем метод ПользователиИнформационнойБазы.ТекущийПользователь() и получаем его уникальный идентификатор:


УникальныйИдентификатор = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
СсылкаНаПользователя = Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ", УникальныйИдентификатор);

Шаг 2. Хранение связи пользователей и участков

Так как одному пользователю может быть разрешен доступ сразу к нескольким участкам, для хранения прав создадим непериодический регистр сведений ДоступПользователейКУчасткам со следующей структурой:

  1. Измерение Пользователь (Тип: СправочникСсылка.Пользователи, Ведущее: Истина).
  2. Измерение Участок (Тип: СправочникСсылка.Участки, Ведущее: Истина).

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

Шаг 3. Кэширование прав в параметрах сеанса

Чтобы не выполнять тяжелые запросы к регистру сведений при каждом открытии формы или проверке прав, сохраним доступные участки в параметрах сеанса. Создадим параметры сеанса ТекущийПользователь (тип: СправочникСсылка.Пользователи) и ДоступныеУчастки (тип: ФиксированныйМассив).

В модуле сеанса в процедуре УстановкаПараметровСеанса заполняем эти параметры:


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

Шаг 4. Настройка разграничения на уровне записей (RLS)

Для гарантированной защиты данных от несанкционированного просмотра и изменения настроим ограничение доступа на уровне записей (RLS) в ролях пользователей.

В правах роли для нужных документов на операцию Чтение прописываем условие ограничения доступа. Сравнение реквизита документа Участок с параметром сеанса выглядит следующим образом:

ГДЕ Участок В (&ДоступныеУчастки)

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

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

Шаг 5. Интерфейсный отбор и автозаполнение документов

Если в конфигурации требуется только комфортная работа пользователей без строгого ограничения прав на уровне СУБД, фильтрацию можно реализовать через динамические списки в формах.

В процедуре ПриСозданииНаСервере формы списка документов устанавливаем отбор:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    ЭлементОтбора = Список.ФиксированныеНастройки.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
    ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Участок");
    ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
    ЭлементОтбора.ПравоеЗначение = ПараметрыСеанса.ДоступныеУчастки;
    ЭлементОтбора.Использование = Истина;
    
КонецПроцедуры

А для автоматического заполнения реквизита Участок при создании новых документов используем процедуру ОбработкаЗаполнения в модуле объекта документа:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    
    Если Не ЗначениеЗаполнено(Участок) Тогда
        Участок = ПараметрыСеанса.ТекущийПользователь.ОсновнойУчасток;
    КонецЕсли;
    
КонецПроцедуры

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

← На главную