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