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