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