Как проверить доступность роли у другого пользователя в 1С, если у текущего нет полных прав?

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

В процессе разработки бизнес-логики в среде «1С:Предприятие 8» часто возникает задача проверки прав доступа и ролей других пользователей системы. Классический пример — рабочее место кассира (РМК). Обычный кассир работает под ограниченными правами и не может редактировать пробитые или закрытые чеки. Однако при возникновении спорной ситуации к нему может подойти старший кассир или администратор, предоставить свою карту авторизации (считать штрихкод или магнитный код), и система должна временно разрешить редактирование документа.

На первый взгляд задача кажется тривиальной: мы находим пользователя по идентификатору карты, получаем объект его учетной записи и проверяем наличие роли. Однако на практике разработчики сталкиваются с тем, что коллекция ролей целевого пользователя оказывается пустой, а попытки вызвать платформенные методы приводят к ошибкам прав доступа. Давайте разберем по шагам, почему возникает эта проблема и как правильно ее решить различными способами.

Выясняем причину: почему не работает стандартный платформенный код?

Посмотрим на типичный код, который часто пытаются использовать начинающие разработчики:


ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(ИдентификаторПользователя);
Если ПользовательИБ.Роли.Содержит(Метаданные.Роли.РедактированиеЧеков) Тогда
    // Разрешаем редактирование
КонецЕсли;

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

Проанализируем ограничения платформы «1С:Предприятие»:

  1. Ограничение менеджера ПользователиИнформационнойБазы: Платформа накладывает жесткие ограничения на доступ к списку пользователей информационной базы. Найти и прочитать данные стороннего пользователя ИБ (включая его роли) может только сеанс, обладающий административными правами. Обычный пользователь через метод НайтиПоУникальномуИдентификатору() может получить только самого себя.
  2. Нюансы работы привилегированного режима: Многие разработчики пытаются обойти это ограничение с помощью вызова УстановитьПривилегированныйРежим(Истина). Однако это не всегда помогает. Если вызов происходит на стороне клиента (в тонком или веб-клиенте), платформа просто проигнорирует инструкцию включения привилегированного режима. Даже на сервере прямое обращение к методам менеджера ПользователиИнформационнойБазы может блокироваться платформенными механизмами защиты, если код выполняется в обычном, а не в специальном привилегированном общем модуле.
  3. Оптимизация состава ролей в БСП: В современных конфигурациях на базе Библиотеки Стандартных Подсистем (БСП) роли назначаются пользователям динамически через профили и группы доступа. Более того, платформа оптимизирует этот список: если у пользователя есть роль «Полные права», то все остальные роли физически отключаются как избыточные. В результате прямая проверка Роли.Содержит() вернет Ложь, даже если логически пользователю доступно это действие.

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

Вариант 1. Использование стандартного программного интерфейса БСП (Рекомендуемый)

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

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

Для проверки выполним следующий код на сервере:


// В качестве параметра "Пользователь" передается ссылка на Справочник.Пользователи
ИмяРоли = "ФанРедактированиеЧека";
УчетнаяЗаписьПользователя = Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторПользователяИБ", НужныйИД);

Если Пользователи.РолиДоступны(ИмяРоли, УчетнаяЗаписьПользователя) Тогда
    // Роль доступна пользователю, выполняем логику
КонецЕсли;

Метод Пользователи.РолиДоступны() принимает несколько параметров:

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

Вариант 2. Прямой запрос к таблицам прав БСП (Быстрый серверный метод)

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

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

Проанализируем структуру запроса и реализуем его по шагам:


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

Разберем, почему этот запрос работает эффективно:

Вариант 3. Использование регистра «Дополнительные права пользователей» (Best Practice для розницы)

В специализированных или торговых решениях (таких как «1С:Розница», «1С:Управление торговлей» или «1С:Комплексная автоматизация») завязываться на жесткие роли метаданных при авторизации по картам считается плохой практикой проектирования. Роли статичны, их структуру нельзя изменить без динамического обновления или доработки конфигурации.

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

Посмотрим, как выглядит архитектура такого решения:

  1. В системе создается или используется типовой регистр сведений ДополнительныеПраваПользователей.
  2. В качестве измерений регистра выступают Пользователь (или ГруппаПользователей) и Право (ПланыВидовХарактеристик). Значением ресурса является Булево или числовое значение.
  3. При считывании карты подтверждения система находит пользователя, привязанного к штрихкоду карты.
  4. В привилегированном режиме выполняется простой и быстрый запрос к регистру сведений.

Рассмотрим пример реализации такой проверки:


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

Использование регистра дополнительных прав имеет массу преимуществ перед анализом ролей метаданных:

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

← На главную