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