В практической работе администраторов и разработчиков 1С часто возникает задача: необходимо проверить, имеет ли определенный пользователь доступ на чтение или изменение конкретного экземпляра документа (например, ЗаказПокупателя). Ситуация осложняется, если в системе настроен сложный, разветвленный механизм ограничения доступа на уровне записей (RLS — Record Level Security).
Обычный пользователь с полными правами должен иметь возможность выбрать в интерфейсе тестируемого сотрудника, указать целевой документ и мгновенно получить вердикт: разрешен доступ или нет. Разберем по шагам, как решить эту задачу красиво, надежно и с учетом особенностей различных версий платформы и конфигураций.
ПравоДоступа() не подходит?Первое, что часто приходит на ум начинающим разработчикам — использовать стандартную функцию платформы ПравоДоступа(). Однако этот метод проверяет права доступа только на уровне метаданных (то есть к типу документа в целом). Он отвечает на вопрос: «Имеет ли пользователь в принципе право читать документы вида ЗаказПокупателя согласно своим ролям?». Ответить на вопрос, разрешен ли доступ к конкретной сделке с учетом ограничений по организациям, контрагентам или подразделениям, функция ПравоДоступа() не способна.
Для решения этой задачи мы рассмотрим три надежных архитектурных подхода, а также разберем, почему популярный на форумах способ с «подменой параметров сеанса» является опасным и нерабочим.
Если вы работаете в современной конфигурации, построенной на базе Библиотеки стандартных подсистем (БСП) версии 3.1 и выше, разработчики 1С уже предусмотрели штатный и максимально простой инструмент.
В общем модуле УправлениеДоступом функции проверки прав поддерживают необязательный параметр Пользователь. Мы можем использовать следующие функции:
УправлениеДоступом.ЧтениеРазрешено(ОписаниеДанных, Пользователь) — проверяет, разрешено ли чтение конкретного объекта (ссылки на документ) для указанного пользователя информационной базы.УправлениеДоступом.ИзменениеРазрешено(ОписаниеДанных, Пользователь) — проверяет права на изменение конкретного объекта для указанного пользователя.Рассмотрим пример кода для проверки прав:
// Определим проверяемый документ и пользователя
ДокументСсылка = Документы.ЗаказПокупателя.НайтиПоНомеру("000000001", ТекущаяДата());
ПроверяемыйПользователь = Справочники.Пользователи.НайтиПоНаименованию("Иванов Иван Иванович");
// Проверим права доступа на чтение
ДоступРазрешен = УправлениеДоступом.ЧтениеРазрешено(ДокументСсылка, ПроверяемыйПользователь);
Если ДоступРазрешен Тогда
Сообщить("Пользователь имеет доступ к документу.");
Иначе
Сообщить("Доступ к документу для данного пользователя ограничен.");
КонецЕсли;
Важные нюансы работы метода:
УправлениеДоступом.ПроизводительныйВариант().В современных конфигурациях (таких как ERP 2, Комплексная автоматизация 2, Управление торговлей 11, Бухгалтерия предприятия 3.0) при включенном производительном режиме RLS права рассчитываются системой заранее и кэшируются в специальных служебных регистрах сведений.
Для проверки мы можем напрямую обратиться к двум регистрам:
РегистрСведений.КлючиДоступаКОбъектам — хранит информацию о соответствии конкретных документов (объектов) и их хэш-ключей доступа.РегистрСведений.КлючиДоступаПользователей — связывает пользователей (или их группы доступа) со списком доступных им ключей.Благодаря этому администратор под полными правами может написать один простой и очень быстрый запрос без необходимости переключения сеансов или запуска фоновых процессов. Проанализируем пример такого запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ Первые 1
| КлючиОбъектов.Ссылка ИЗ
| РегистрСведений.КлючиДоступаКОбъектам КАК КлючиОбъектов
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КлючиДоступаПользователей КАК КлючиПользователей
| ПО КлючиОбъектов.КлючДоступа = КлючиПользователей.КлючДоступа
|ГДЕ
| КлючиОбъектов.Ссылка = &СсылкаНаДокумент
| И КлючиПользователей.Пользователь = &ПроверяемыйПользователь";
Запрос.УстановитьПараметр("СсылкаНаДокумент", ОбъектПроверки);
Запрос.УстановитьПараметр("ПроверяемыйПользователь", ТестируемыйПользователь);
РезультатЗапроса = Запрос.Выполнить();
ДоступЕсть = НЕ РезультатЗапроса.Пустой();
Этот способ работает мгновенно даже на огромных базах данных, поскольку он не задействует механизмы динамического расчета прав платформы, а использует уже готовые, кэшированные индексы СУБД.
Если в вашей конфигурации используется старый (обычный) режим RLS или система не базируется на современных версиях БСП, лучшим решением будет использование механизма фоновых заданий. Суть метода заключается в том, чтобы запустить изолированный рабочий поток (сеанс) непосредственно под учетной записью проверяемого пользователя и выполнить в нем простой запрос с ключевым словом РАЗРЕШЕННЫЕ.
Рассмотрим пошагово, как это реализовать программно:
Шаг 1. Создание экспортной процедуры в общем модуле
Процедура должна быть размещена в общем модуле с флагом "Сервер" и вызывать проверку наличия документа в базе через запрос.
// Процедура должна быть доступна для фонового задания
Процедура ПроверитьДоступФоновое(ПараметрыПроверки, АдресРезультата) Экспорт
СсылкаНаДокумент = ПараметрыПроверки.Ссылка;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ
| Ссылка
|ИЗ
| Документ.ЗаказПокупателя
|ГДЕ
| Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Результат = Запрос.Выполнить();
ДоступЕсть = НЕ Результат.Пустой();
ПоместитьВоВременноеХранилище(ДоступЕсть, АдресРезультата);
КонецПроцедуры
Шаг 2. Запуск фонового задания под правами тестируемого пользователя
В коде интерактивной обработки (откуда администратор запускает проверку) мы инициируем фоновое задание, передавая в метод ФоновыеЗадания.Выполнить() пользователя информационной базы:
АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, Новый УникальныйИдентификатор);
ПараметрыПроцедуры = Новый Структура("Ссылка", ПроверяемыйДокумент);
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(ПараметрыПроцедуры);
МассивПараметров.Добавить(АдресРезультата);
// Находим объект ПользовательИнформационнойБазы для авторизации задания
ИмяПользователяИБ = ПроверяемыйПользователь.Имя; // Справочник "Пользователи"
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(ИмяПользователяИБ);
// Запуск задания под правами конкретного пользователя
НовоеЗадание = ФоновыеЗадания.Выполнить(
"ИмяОбщегоМодуля.ПроверитьДоступФоновое",
МассивПараметров,
"ПроверкаДоступаПодПользователем",
ПользовательИБ
);
Попытка
НовоеЗадание.ОжидатьЗавершения(10); // Ожидаем выполнения не более 10 секунд
ДоступРазрешен = ПолучитьИзВременногоХранилища(АдресРезультата);
Исключение
Сообщить("Ошибка выполнения проверки прав: " + ОписаниеОшибки());
КонецПопытки;
Этот метод абсолютно безопасен. Фоновое задание работает в изолированном контексте, использует реальное окружение прав тестируемого пользователя и гарантирует 100% достоверный результат.
Среди разработчиков часто встречается идея временно подменить параметр сеанса (например, ПараметрыСеанса.ТекущийПользователь = ТестируемыйПользователь), выполнить обычный запрос с ключевым словом РАЗРЕШЕННЫЕ в текущем сеансе администратора, а затем вернуть параметр назад.
Настоятельно не рекомендуем использовать этот подход по следующим причинам:
Используйте проверенные штатные функции БСП или фоновые задания, чтобы гарантировать стабильность и безопасность вашей системы 1С!