Где лучше ставить ограничения по ролям для элементов: в модуле объекта или в форме документа?

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

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

Различие между видимостью интерфейса и защитой данных

Прежде всего, нам необходимо четко разделить два понятия: пользовательский интерфейс (UI) и целостность данных. Программисты часто совершают ошибку, полагая, что скрытие поля на форме является надежной защитой. Рассмотрим, почему это не так:

  1. Ограничение на форме: Когда мы пишем ЭлементыФормы.Реквизит.Видимость = Ложь, мы лишь делаем элемент невидимым для человеческого глаза. Однако сам реквизит в базе данных остается доступным. Любой продвинутый пользователь или администратор может запустить внешнюю обработку "Групповое изменение реквизитов" и поменять значение этого поля, даже если на форме оно скрыто.
  2. Ограничение в модуле объекта: Проверки в модуле объекта (например, в событии ПередЗаписью) работают на уровне ядра платформы. Независимо от того, откуда пришла команда на запись — из формы документа, из обработки обмена данными или из регламентного задания — код в модуле объекта будет выполнен. Это и есть настоящая защита данных.

Проанализируем ситуацию: если ваша задача — сделать работу пользователя удобнее, используйте модуль формы. Если задача — запретить редактирование важной информации (например, цен или счетов учета) определенным категориям сотрудников — обязательно используйте модуль объекта.

Реализация ограничений в модуле формы (UX-подход)

Рассмотрим пример кода для обычных форм, который позволяет управлять доступностью элементов в зависимости от ролей пользователя. Чаще всего такую проверку размещают в процедуре ПриОткрытии или ПриУстановкеНовогоНомера (если логика зависит от того, новый это объект или нет).

Посмотрим на пример реализации, где мы проверяем права на чтение и изменение, а затем динамически настраиваем элементы формы:


Процедура ПриОткрытии()
    
    // Если у пользователя полные права, никакие ограничения не накладываем
    Если РольДоступна("ПолныеПрава") Тогда 
        Возврат; 
    КонецЕсли;

    // Определяем наличие конкретных ролей
    ЕстьПравоЧтения = РольДоступна("МенеджерПоПродажам");
    ЕстьПравоИзменения = РольДоступна("РуководительОтдела");
    
    ИмяЭлемента = "ТабличнаяЧастьТовары";
    
    // Настраиваем видимость: элемент виден, если есть хоть какое-то право
    Видимость = (ЕстьПравоЧтения ИЛИ ЕстьПравоИзменения);
    ЭлементыФормы[ИмяЭлемента].Видимость = Видимость;
    
    // Настраиваем возможность редактирования
    ТолькоПросмотр = НЕ ЕстьПравоИзменения;
    ЭлементыФормы[ИмяЭлемента].ТолькоПросмотр = ТолькоПросмотр;

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

В данном примере мы используем стандартную функцию РольДоступна(). Важно помнить, что в обычных формах этот код выполняется на стороне клиента, но обращается к серверу для проверки прав, поэтому не стоит злоупотреблять такими вызовами в циклах.

Реализация жестких ограничений в модуле объекта (Безопасность)

Теперь разберем, как гарантированно защитить данные от несанкционированного изменения. Лучшее место для этого — событие ПередЗаписью в модуле объекта. Здесь мы можем сравнить текущее состояние объекта с тем, что уже записано в базе данных.

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)

    // Проверяем роль. Если роль доступна, выходим из проверки.
    Если РольДоступна("РазрешитьИзменениеЦен") ИЛИ ЭтоНовый() Тогда
        Возврат;
    КонецЕсли;

    // Сравниваем текущие данные с данными в БД
    // Для этого получаем 'старую' версию объекта через ссылку
    СсылкаНаОбъект = ЭтотОбъект.Ссылка;
    Если СсылкаНаОбъект.Пустая() Тогда
        Возврат; // Это новый объект, логика может быть другой
    КонецЕсли;

    ИсходныйОбъект = СсылкаНаОбъект.ПолучитьОбъект();
    
    // Пример проверки изменения табличной части "Товары"
    // Выгружаем ТЧ в таблицы значений для быстрого сравнения
    ТаблицаБД = ИсходныйОбъект.Товары.Выгрузить();
    ТекущаяТаблица = ЭтотОбъект.Товары.Выгрузить();
    
    // Сравниваем значения. Если таблицы не идентичны — значит была попытка правки
    Если НЕ ОбщегоНазначения.ТаблицыЗначенийИдентичны(ТаблицаБД, ТекущаяТаблица) Тогда
        Отказ = Истина;
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "У вас нет прав на изменение состава товаров в этом документе!";
        Сообщение.Сообщить();
        Возврат;
    КонецЕсли;

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

Важный нюанс: метод ПолучитьОбъект() внутри модуля объекта создает новый экземпляр данных из базы. Это позволяет нам увидеть состояние реквизитов "до начала редактирования". Однако помните о производительности: частое использование ПолучитьОбъект() в высоконагруженных системах может замедлить запись документов.

Централизация логики в общих модулях

Писать один и тот же код проверки ролей в каждой форме — плохая практика (дублирование кода). Если правила проверки прав одинаковы для нескольких документов, логику следует вынести в Общий модуль.

Разберем, как это сделать правильно. Создадим общий модуль УправлениеПравамиДоступаСлужебный и разместим там функцию, которая будет возвращать структуру прав для текущего пользователя. Это позволит нам один раз описать правила и использовать их повсеместно.


// В общем модуле
Функция ПолучитьПраваПользователяНаДокумент(ДокументОбъект) Экспорт
    
    Результат = Новый Структура;
    Результат.Вставить("МожноРедактироватьЦены", РольДоступна("ПолныеПрава") ИЛИ РольДоступна("РедактированиеЦен"));
    Результат.Вставить("МожноМенятьСклады", РольДоступна("ПолныеПрава") ИЛИ РольДоступна("АдминистрированиеСкладов"));
    
    Возврат Результат;
    
КонецФункции

Теперь в любой форме документа мы можем просто вызвать эту функцию:


Права = УправлениеПравамиДоступаСлужебный.ПолучитьПраваПользователяНаДокумент(ЭтотОбъект);
ЭлементыФормы.Цена.ТолькоПросмотр = НЕ Права.МожноРедактироватьЦены;

Проблема проверки роли "ПолныеПрава"

В коде часто встречается конструкция Если РольДоступна("ПолныеПрава"). Мы должны предостеречь вас от использования жестко прописанных имен ролей. В крупных конфигурациях или при использовании Библиотеки Стандартных Подсистем (БСП) имя роли может измениться, или может быть создана новая роль с неограниченными правами (например, "Администратор").

Рекомендуется использовать методы БСП, такие как Пользователи.РольДоступна() или проверять наличие административных прав через привилегированные модули. Также хорошим тоном считается проверка не "Роли", а "Права". Например, вместо проверки роли "Бухгалтер", лучше проверять право на конкретное действие, используя функциональные опции.

Использование функциональных опций (ФО)

Если вы работаете в современной конфигурации, проанализируйте возможность использования Функциональных опций. Это мощный механизм платформы, который позволяет:

В свойствах элемента формы в конфигураторе есть раздел "Функциональные опции". Достаточно указать там нужную ФО, и платформа сама будет управлять видимостью элемента в зависимости от прав или настроек системы.

Итоговые рекомендации: где все-таки ставить ограничения?

Подведем итог нашему анализу. Выясним оптимальную схему работы для профессионального разработчика 1С:

  1. Дублируйте проверку: Используйте модуль формы для того, чтобы скрыть лишнее от пользователя (UX). Используйте модуль объекта, чтобы исключить программный взлом данных (Безопасность).
  2. Приоритет общему модулю: Выносите логику определения прав в общие модули. Это облегчит поддержку кода, когда названия ролей или требования бизнеса изменятся.
  3. Обычные vs Управляемые формы: В управляемых формах помните, что проверка ролей должна происходить на сервере (обычно в ПриСозданииНаСервере), а результат передаваться на клиент в виде простых булевых переменных.
  4. Используйте БСП: Если ваша конфигурация основана на современных типовых решениях, всегда отдавайте приоритет встроенным механизмам подсистемы "Управление доступом".

Следуя этим правилам, вы создадите надежную и удобную систему разграничения прав, которая будет защищена от ошибок пользователей и некорректных программных воздействий.

← На главную