В практике разработчика 1С часто возникает ситуация, когда необходимо изменить права доступа для определенной группы пользователей в типовой конфигурации. Особенно остро этот вопрос встает, когда конфигурация находится на поддержке и обновляется путем загрузки файла .cf из центрального офиса или от вендора. В этом случае любые изменения в основных ролях будут затерты при очередном обновлении. Казалось бы, логичное решение — создать роль в расширении, но здесь мы сталкиваемся с фундаментальным принципом работы системы прав 1С.
В данной статье мы разберем, почему нельзя просто «запретить» действие новой ролью, и рассмотрим пошаговые алгоритмы решения задачи через механизмы расширений, включая программные проверки и использование подписок на события.
Прежде чем переходить к коду, проанализируем, почему стандартное создание роли в расширении не помогает «урезать» права. В платформе «1С:Предприятие 8.3» права пользователя суммируются по принципу логического «ИЛИ». Если пользователю назначено несколько ролей, и хотя бы одна из них разрешает проведение документа РеализацияТоваровУслуг, то никакая другая роль не может это действие запретить.
Следовательно, если в основной конфигурации у пользователя есть роль МенеджерПродаж, которая дает право на проведение, создание в расширении роли без этого права ничего не изменит. Нам необходимо найти способ программного вмешательства, который сработает «поверх» установленных прав. Рассмотрим варианты реализации.
Этот метод считается наиболее «чистым» и современным для версий платформы 8.3.17 и выше. Суть заключается в том, что мы создаем роль в расширении не для управления правами доступа на уровне метаданных, а как флаг (маркер) для конкретной группы пользователей.
Рассмотрим алгоритм реализации:
ЗапретПроведенияРеализаций. В самой роли не нужно настраивать права на объекты — она будет служить лишь идентификатором.ПодпискаНаСобытие.ДокументОбъект.РеализацияТоваровУслуг).ПередЗаписью.Теперь разберем программный код в модуле расширения, который будет обрабатывать это событие. Проанализируем ситуацию: нам нужно запретить только проведение, но оставить возможность записи документа.
Процедура Расш1_ПередЗаписьюДокументаПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// Проверяем, что выполняется именно проведение документа
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
// Проверяем наличие нашей специальной роли у текущего пользователя
Если РольДоступна("ЗапретПроведенияРеализаций") Тогда
// Выводим сообщение пользователю и отменяем действие
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "У вас недостаточно прав для проведения данного документа. Обратитесь к администратору.";
Сообщение.Сообщить();
Отказ = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное примечание: Если ваше расширение имеет префикс (например, Расш1_), то при проверке роли методом РольДоступна() необходимо учитывать, как платформа интерпретирует имена ролей из расширений. Обычно используется синтаксис ИмяРасширения_ИмяРоли.
Если версия вашей платформы ниже 8.3.17, возможность создания подписок на события в расширении может быть ограничена. В этом случае мы воспользуемся механизмом заимствования методов. Рассмотрим, как это сделать без изменения основного кода.
Нам необходимо заимствовать процедуру ОбработкаПроведения или ПередЗаписью непосредственно в модуль объекта документа внутри расширения. Рекомендуется использовать аннотацию &Перед, чтобы логика проверки сработала до начала транзакции проведения.
Посмотрим на пример реализации в модуле объекта расширения:
&Перед("ОбработкаПроведения")
Процедура Расш1_ОбработкаПроведения(Отказ, РежимПроведения)
// Проверяем права программно
Если РольДоступна("ЗапретПроведенияРеализаций") Тогда
Отказ = Истина;
ВызватьИсключение "Операция проведения запрещена для вашего профиля доступа!";
КонецЕсли;
КонецПроцедуры
Почему мы выбираем &Перед? Проанализируем: если мы поставим проверку в &После, основной код проведения уже выполнится, движения будут сформированы, и хотя установка Отказ = Истина все равно отменит транзакцию, это будет менее производительно и может привести к выполнению лишних тяжелых операций на сервере.
Выясним причину, почему у некоторых разработчиков не получается создать подписку в расширении. Как было отмечено в обсуждении, ключевым фактором является версия платформы:
&Перед, &После или &Вместо для существующих процедур модулей.Если вы работаете с современной конфигурацией (например, БП 3.0, УТ 11, ERP 2), стоит рассмотреть возможность интеграции вашего решения в общую систему управления доступом Библиотеки Стандартных Подсистем (БСП).
Вместо жесткой проверки РольДоступна(), можно создать свой Вид доступа в расширении и использовать программные интерфейсы БСП для проверки прав. Однако для простой задачи «запретить проведение одной группе» создание подписки в расширении является «золотым стандартом», так как оно полностью изолировано от типового кода.
Проанализируем шаги, которые нужно предпринять для успешного запуска решения:
Отказ = Истина. Убедитесь, что при отказе пользователю выдается понятное сообщение, иначе служба поддержки будет завалена вопросами о «непонятном сбое»..cf ваше расширение останется неизменным. Однако, если в основной конфигурации изменятся параметры заимствованных процедур (например, в ПередЗаписью добавят новый параметр), расширение может перестать применяться. В этом случае достаточно будет обновить сигнатуру метода в расширении.Таким образом, мы видим, что даже при невозможности изменения состава ролей основной конфигурации, механизм расширений предоставляет гибкие инструменты для тонкой настройки прав доступа через программный слой. Использование роли-маркера в сочетании с подпиской на событие позволяет реализовать сложную логику запретов, не нарушая целостность типового решения.