Как обойти ошибку «Пользователю недостаточно прав» при вызове ПользователиИнформационнойБазы.ПолучитьПользователей() в 1С?

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

При разработке пользовательских обработок, чатов, механизмов оповещений или задач часто возникает потребность получить список пользователей информационной базы. Однако при выполнении кода под учетной записью с ограниченными правами (без административных полномочий) вызов метода ПользователиИнформационнойБазы.ПолучитьПользователей() завершается системным исключением «Пользователю недостаточно прав для выполнения операции».

Выясним причину такого поведения платформы и разберем несколько корректных способов решения этой задачи без предоставления рядовым пользователям полных административных прав.

Почему возникает ошибка доступа

Проанализируем архитектуру платформы «1С:Предприятие». Метод ПользователиИнформационнойБазы.ПолучитьПользователей() обращается напрямую к системным таблицам учетных записей. Для его успешного выполнения у текущей роли пользователя обязательно должны быть установлены системные права Администрирование или АдминистрированиеДанных.

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

Способ 1. Использование программной установки привилегированного режима

Разберем самый быстрый способ обхода проверки прав. Платформа 1С позволяет временно отключить проверку прав доступа и ограничений на уровне записей (RLS) на сервере с помощью вызова специального метода.

Посмотрим на пример реализации в серверной процедуре или функции:


&НаСервере
Функция ПолучитьСписокПользователейИБНаСервере()
    
    УстановитьПривилегированныйРежим(Истина);
    
    МассивПользователейИБ = ПользователиИнформационнойБазы.ПолучитьПользователей();
    
    СписокИмен = Новый Массив;
    Для Каждого ПользовательИБ Из МассивПользователейИБ Цикл
        СписокИмен.Добавить(ПользовательИБ.Имя);
    КонецЦикла;
    
    УстановитьПривилегированныйРежим(Ложь);
    
    Возврат СписокИмен;
    
КонецФункции

Обратим внимание на важные правила работы с привилегированным режимом:

  1. Метод УстановитьПривилегированныйРежим() работает только на стороне сервера, во внешнем соединении или в привилегированных модулях. На клиенте вызвать его невозможно.
  2. Всегда рекомендуется отключать привилегированный режим вызовом УстановитьПривилегированныйРежим(Ложь) сразу после выполнения критической операции, чтобы не оставлять сеанс без контроля прав.

Способ 2. Вынос логики в привилегированный общий модуль

Согласно стандартам разработки «1С», наиболее надежным и безопасным подходом является создание отдельного общего модуля с включенным свойством Привилегированный. Это исключает необходимость вручную управлять флагами привилегированного режима в коде форм или обработок.

Разберем по шагам создание такого механизма:

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

Функция ПолучитьСписокИменПользователей() Экспорт
    
    Результат = Новый Массив;
    МассивПользователей = ПользователиИнформационнойБазы.ПолучитьПользователей();
    
    Для Каждого ТекПользователь Из МассивПользователей Цикл
        Результат.Добавить(Новый Структура("Имя, ПолноеИмя, УникальныйИдентификатор", 
            ТекПользователь.Имя, 
            ТекПользователь.ПолноеИмя, 
            ТекПользователь.УникальныйИдентификатор));
    КонецЦикла;
    
    Возврат Результат;
    
КонецФункции

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


&НаКлиенте
Процедура ЗаполнитьПользователей(Команда)
    
    ДанныеПользователей = ПользователиСерверПривилегированный.ПолучитьСписокИменПользователей();
    // Заполнение элементов формы полученными данными
    
КонецПроцедуры

Способ 3. Использование справочника пользователей вместо системных таблиц

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

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


&НаСервере
Функция ПолучитьСписокАктивныхПользователей()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Пользователи.Ссылка КАК Пользователь,
        |	Пользователи.Наименование КАК ПолноеИмя,
        |	Пользователи.ИдентификаторПользователяИБ КАК Идентификатор
        |ИЗ
        |	Справочник.Пользователи КАК Пользователи
        |ГДЕ
        |	НЕ Пользователи.ПометкаУдаления
        |	И НЕ Пользователи.Недействителен";
        
    Возврат Запрос.Выполнить().Выгрузить();
    
КонецФункции

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

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

← На главную