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