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