Как настроить RLS, чтобы ограничить доступ одним пользователям и оставить его другим

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

При настройке системы прав доступа в 1С разработчики часто сталкиваются с задачей ограничения видимости данных на уровне записей (Record Level Security — RLS). Классический пример: кладовщик Вася должен видеть поступления только по своему складу, а менеджер Петя должен иметь доступ ко всем складам компании. Если прописать простое ограничение в лоб через запрос к регистру сведений, можно столкнуться с ситуацией, когда пользователи без записей в этом регистре перестают видеть данные вообще. Разберем, как правильно реализовать такую логику, обеспечив при этом высокую производительность системы.

Анализ проблемы: почему "Петя не видит ничего"

Рассмотрим ситуацию, описанную в исходном вопросе. Разработчик создал регистр ДоступностьПоСкладам и прописал в роли следующее ограничение:


ТекущаяТаблица ГДЕ ТекущаяТаблица.Склад В
    (ВЫБРАТЬ
        ДоступностьПоСкладам.ДоступныйСклад
    ИЗ
        РегистрСведений.ДоступностьПоСкладам КАК ДоступностьПоСкладам
    ГДЕ
        ДоступностьПоСкладам.Пользователь = &ТекущийПользователь)

Проанализируем этот запрос. Когда система проверяет права для Васи, у которого в регистре есть запись "Склад афроамериканцев", запрос возвращает этот склад, и условие В (Список) срабатывает. Однако для Пети записей в регистре нет. Вложенный запрос возвращает пустой результат. С точки зрения SQL условие превращается в Склад В (ПУСТОЙ_СПИСОК), что всегда ложно. В итоге Петя не видит ни одной записи. Нам же нужно реализовать логику: "Если записей в регистре нет — разрешить всё".

Решение 1: Разделение ролей (Самый простой способ)

Прежде чем погружаться в сложные запросы RLS, проанализируем архитектуру ролей. В 1С права суммируются по принципу ЛОГИЧЕСКОГО ИЛИ. Если пользователю назначено несколько ролей, и хотя бы одна из них разрешает чтение записи без ограничений, то ограничения из других ролей будут проигнорированы платформой.

Рассмотрим по шагам, как это применить:

  1. Создадим роль Склады_ОграничениеПоСкладам, где пропишем запрос RLS для Васи.
  2. Создадим роль Склады_ПолныйДоступ, где не будет никаких ограничений RLS на справочник Склады и связанные документы.
  3. Назначим Васе только первую роль, а Пете — вторую (или обе).

В этом случае платформа увидит, что у Пети есть роль без RLS, и не будет тратить ресурсы на выполнение дополнительных проверок в запросах. Это самый производительный метод.

Решение 2: Использование параметров сеанса (Оптимальный вариант)

Использование вложенных запросов непосредственно в тексте RLS (как в примере с ВЫБРАТЬ... ИЗ ДоступностьПоСкладам) — это "антипаттерн". Такой запрос будет выполняться СУБД для каждой проверки, что может существенно замедлить работу динамических списков и отчетов. Рассмотрим более профессиональный подход с использованием ПараметровСеанса.

Шаг 1. Создание параметра сеанса. Создадим параметр сеанса ДоступныеСклады с типом ФиксированныйМассив.

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

Шаг 3. Настройка RLS через шаблон. Пропишем условие в роли, используя логику "разрешено всё, если маркер присутствует":


ТекущаяТаблица ИЗ #ТекущаяТаблица КАК ТекущаяТаблица
ГДЕ ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка) В (&ДоступныеСклады)
  ИЛИ ТекущаяТаблица.Склад В (&ДоступныеСклады)

Проанализируем работу этого условия: если мы добавили в массив &ДоступныеСклады пустую ссылку для Пети, то первое условие ЗНАЧЕНИЕ(...) В (&ДоступныеСклады) всегда будет истинным для любой строки таблицы. Платформа оптимизирует такой запрос, и Петя получит доступ ко всем данным быстро.

Решение 3: Реализация логики "Если пусто, то можно всё" в одном запросе

Если по каким-то причинам использование параметров сеанса невозможно, и нужно решить задачу только средствами запроса RLS, можно использовать проверку на наличие записей в регистре. Разберем, как это сделать:


ТекущаяТаблица ГДЕ (НЕ 1 В 
    (ВЫБРАТЬ ПЕРВЫЕ 1 1 
     ИЗ РегистрСведений.ДоступностьПоСкладам КАК Т 
     ГДЕ Т.Пользователь = &ТекущийПользователь))
ИЛИ ТекущаяТаблица.Склад В 
    (ВЫБРАТЬ ДоступностьПоСкладам.ДоступныйСклад 
     ИЗ РегистрСведений.ДоступностьПоСкладам КАК ДоступностьПоСкладам 
     ГДЕ ДоступностьПоСкладам.Пользователь = &ТекущийПользователь)

Как это работает:

  1. Первая часть (до ИЛИ) проверяет, есть ли вообще записи для данного пользователя в регистре прав. Если записей нет, условие НЕ 1 В (...) возвращает истину, и доступ разрешается ко всем записям таблицы.
  2. Вторая часть (после ИЛИ) работает только если в регистре есть настройки, ограничивая выборку конкретными складами.

Оптимизация производительности: Индексы и селективность

Когда мы работаем с RLS, крайне важно, чтобы СУБД могла эффективно использовать индексы. Проанализируем рекомендации по настройке регистра ДоступностьПоСкладам:

Современный стандарт: Библиотека стандартных подсистем (БСП)

В современных конфигурациях (таких как ERP, КА 2 или УТ 11) крайне редко пишут запросы RLS вручную. Рассмотрим, как это реализовано в подсистеме "Управление доступом" БСП. Вместо написания кода программист настраивает "Виды доступа".

Для нашей задачи это выглядело бы так:

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

Нюансы работы с NULL и пустыми значениями

При написании запросов RLS важно помнить о поведении NULL. Если вы используете ЛЕВОЕ СОЕДИНЕНИЕ для проверки прав и запись в таблице прав отсутствует, результатом будет NULL. Любое сравнение с NULL (например, Склад = NULL) дает результат "Ложь", и запись будет скрыта. Всегда используйте ЕСТЬNULL(Поле, Значение) или конструкцию В (ВЫБРАТЬ...), чтобы избежать случайного скрытия данных.

Отладка и проверка

Выясним, как проверить, правильно ли работает наше ограничение. Использовать обычную консоль запросов недостаточно, так как она часто запускается с полными правами. Рекомендуем следующие шаги:

  1. Запустите сеанс под пользователем "Вася".
  2. Воспользуйтесь специализированной "Консолью RLS" (доступна в составе инструментов разработчика). Она позволяет увидеть реальный SQL-текст, который платформа отправляет на сервер базы данных.
  3. Проверьте "Привилегированный режим". Если в коде (например, в общем модуле) выполняется расчет остатков, который должен игнорировать RLS, убедитесь, что этот код обернут в УстановитьПривилегированныйРежим(Истина).

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

← На главную