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