В процессе сопровождения типовых конфигураций «1С:Предприятие 8» программисты часто сталкиваются с требованиями клиентов ограничить доступ к изменению конкретных объектов для определенных пользователей. При этом ключевым условием является сохранение конфигурации на полной поддержке. Единственным верным инструментом в таком случае выступает механизм расширений.
Однако задача существенно усложняется, если целевые пользователи обладают «Полными правами» или широким набором типовых ролей. В рамках этой статьи мы подробно разберем, почему стандартный ролевой механизм не позволяет решить задачу «напрямую», проанализируем возможные архитектурные подходы и разработаем надежное решение с использованием программного кода и регистра сведений в расширении.
Прежде чем перейти к практической реализации, выясним причину, по которой стандартное добавление ролей в расширение часто не приносит желаемого результата. В системе «1С:Предприятие» права доступа рассчитываются по принципу логического «ИЛИ» (аддитивность прав). Это означает следующее:
Попытка создать роль в расширении с целью ограничить пользователя, у которого в основной конфигурации назначена роль ПолныеПрава или ДобавлениеИзменениеДанныхБухгалтерии, заведомо обречена на провал. Единственный способ решить задачу через роли — полностью лишить пользователя типовых ролей с избыточными правами, создать в расширении собственную роль со всеми необходимыми разрешениями (кроме целевых справочников) и назначить её пользователю. Однако этот путь крайне трудоемок, так как требует поддержки огромного массива прав в актуальном состоянии при обновлениях конфигурации.
Для решения нашей задачи мы рассмотрим альтернативный, гораздо более гибкий и надежный подход — программное ограничение доступа через объектную логику в расширении.
Проанализируем ситуацию и выделим два основных метода программного перехвата действий пользователя:
ПриСозданииНаСервере или ПриОткрытии для установки свойства ТолькоПросмотр = Истина. Этот метод прост в реализации, однако он не обеспечивает стопроцентной безопасности. Пользователь сможет обойти это ограничение, используя механизмы группового изменения реквизитов, внешние обработки загрузки данных или программный код.ПередЗаписью в модуле объекта заимствованного справочника. Этот метод является наиболее надежным, так как срабатывает при любой попытке записи элемента в базу данных, независимо от того, как именно и откуда инициировано изменение (из формы элемента, из формы списка, программно или через групповую обработку).Для достижения наилучшего результата мы объединим оба подхода: программно заблокируем запись объекта в базу данных и одновременно сделаем форму недоступной для редактирования, чтобы обеспечить комфортную работу пользователя.
Хардкодить (прописывать жестко в коде) имена конкретных пользователей, которым запрещено редактирование, крайне не рекомендуется. Это лишает систему гибкости. Гораздо профессиональнее создать в расширении специальный регистр настроек доступа.
Рассмотрим подробнее процесс настройки и программирования нашей системы ограничения доступа.
Добавим в наше расширение новый регистр сведений, который назовем, например, настройка_ПраваДоступаПользователей. Настроим его структуру следующим образом:
Пользователь: Тип СправочникСсылка.Пользователи.ИмяОбъектаМетаданных: Тип Строка (длина 150) или заимствованный справочник СправочникСсылка.ИдентификаторыОбъектовМетаданных. Использование строки проще для быстрой разработки.ЗапрещеноРедактирование: Тип Булево.В режиме «1С:Предприятие» администратор сможет создать запись: например, для пользователя «Иванов И.И.» указать объект «Справочник.НоменклатурныеГруппы» и установить флаг в значение Истина.
Для реализации проверки нам необходимо заимствовать в расширение те справочники, редактирование которых нужно ограничить (в нашем примере это НоменклатурныеГруппы и СтатьиЗатрат). Перенесем их в расширение, кликнув правой кнопкой мыши по объекту в конфигураторе и выбрав команду «Добавить в расширение».
В модуле объекта каждого заимствованного справочника нам необходимо перехватить событие записи. Мы воспользуемся аннотацией &Перед для расширения процедуры модуля объекта ПередЗаписью.
Посмотрим на пример программного кода, который решает эту задачу:
&Перед("ПередЗаписью")
Процедура настройка_ПередЗаписью(Отказ, Замещение)
// 1. Исключаем проверку при обмене данными, чтобы не нарушать синхронизацию баз
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// 2. Исключаем фоновые задания и системные процессы, если это необходимо
Если ПараметрыСеанса.УстановленыПараметрыСеанса И НЕ ЗначениеЗаполнено(ПараметрыСеанса.ТекущийПользователь) Тогда
Возврат;
КонецЕсли;
// 3. Получаем имя текущего справочника
ИмяСправочника = ЭтотОбъект.Метаданные().ПолноеИмя();
ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
// Найдем соответствующего пользователя в справочнике Пользователи
СсылкаНаПользователя = Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ", ТекущийПользователь.УникальныйИдентификатор);
Если ЗначениеЗаполнено(СсылкаНаПользователя) Тогда
// Выполняем запрос к нашему регистру сведений
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| настройка_ПраваДоступаПользователей.ЗапрещеноРедактирование КАК ЗапрещеноРедактирование
|ИЗ
| РегистрСведений.настройка_ПраваДоступаПользователей КАК настройка_ПраваДоступаПользователей
|ГДЕ
| настройка_ПраваДоступаПользователей.Пользователь = &Пользователь
| И настройка_ПраваДоступаПользователей.ИмяОбъектаМетаданных = &ИмяОбъектаМетаданных";
Запрос.УстановитьПараметр("Пользователь", СсылкаНаПользователя);
Запрос.УстановитьПараметр("ИмяОбъектаМетаданных", ИмяСправочника);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Если Выборка.ЗапрещеноРедактирование Тогда
Отказ = Истина;
ВызватьИсключение "Внимание! У Вас нет прав на редактирование и запись элементов справочника """ + ЭтотОбъект.Метаданные().Синоним + """.";
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное примечание: Использование конструкции ВызватьИсключение гарантированно прервет транзакцию записи и выведет информативное сообщение пользователю на экран.
Для того чтобы пользователь не тратил свое время на редактирование реквизитов формы, которую он в итоге все равно не сможет записать, добавим визуальную блокировку. Для этого заимствуем форму элемента нашего справочника и расширим метод ПриСозданииНаСервере.
Разберем по шагам логику обработки формы:
&После("ПриСозданииНаСервере")
Процедура настройка_ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ИмяСправочника = ЭтотОбъект.РеквизитФормыВЗначение("Объект").Метаданные().ПолноеИмя();
ТекущийПользователь = Справочники.Пользователи.ТекущийПользователь();
// Проверим наличие запрета в регистре сведений
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| настройка_ПраваДоступаПользователей.ЗапрещеноРедактирование КАК ЗапрещеноРедактирование
|ИЗ
| РегистрСведений.настройка_ПраваДоступаПользователей КАК настройка_ПраваДоступаПользователей
|ГДЕ
| настройка_ПраваДоступаПользователей.Пользователь = &Пользователь
| И настройка_ПраваДоступаПользователей.ИмяОбъектаМетаданных = &ИмяОбъектаМетаданных";
Запрос.УстановитьПараметр("Пользователь", ТекущийПользователь);
Запрос.УстановитьПараметр("ИмяОбъектаМетаданных", ИмяСправочника);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Если Выборка.ЗапрещеноРедактирование Тогда
// Устанавливаем режим просмотра для всей формы
ЭтотОбъект.ТолькоПросмотр = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Использование свойства формы ТолькоПросмотр = Истина делает все поля ввода неактивными для редактирования, скрывает кнопки записи и удаления, делая работу пользователя комфортной и предсказуемой.
Проанализировав созданный нами механизм, мы можем выделить следующие ключевые достоинства данного подхода:
ПередЗаписью в модуле самого объекта, ни одна сторонняя обработка группового изменения реквизитов или внешняя загрузка не сможет изменить данные в обход установленных правил.Таким образом, использование расширения совместно с объектным кодом перехвата событий и регистром настроек является наиболее профессиональным, стабильным и архитектурно верным решением задачи ограничения доступа к справочникам в среде «1С:Предприятие 8».