Как реализовать запрос пароля при открытии документа в 1С:Предприятии 8.3?

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

При необходимости запроса пароля перед открытием документа в системе 1С:Предприятие 8.3 перед нами встает задача выбора оптимального и безопасного решения. Мы рассмотрим как простой, но обладающий недостатками подход, так и более современные и рекомендованные методы, которые соответствуют стандартам разработки управляемого приложения и обеспечивают лучшую безопасность и масштабируемость.

1. Простое, но устаревшее решение (с использованием модального окна)

Самый прямой и интуитивно понятный способ решения данной задачи, особенно если мы только начинаем знакомиться с программированием в 1С, это использование модального запроса ввода строки в процедуре открытия формы документа. Мы можем реализовать это в модуле формы документа, перехватив событие ПередОткрытием.

Давайте посмотрим на пример кода, который можно разместить в модуле формы документа:


// В МодулеФормы документа

&НаКлиенте
Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
    Пароль = "";
    // Выводим модальное окно для ввода пароля
    ВвестиСтроку(Пароль, "Введите пароль для открытия документа:");
    
    // Проверяем введенный пароль
    Если Пароль <> "Любой" Тогда // Замените "Любой" на ваш реальный пароль
        ПоказатьПредупреждение(,"Неправильный пароль! Документ не будет открыт.");
        Отказ = ИСТИНА; // Отменяем стандартную обработку открытия формы
    КонецЕсли;
КонецПроцедуры

Анализируем этот подход:

  1. Простота реализации: Этот метод очень прост в реализации и быстро позволяет достичь требуемого функционала.
  2. Место кода: Код располагается непосредственно в МодулеФормы документа, что соответствует предположению автора вопроса.
  3. Недостатки модальных окон: Однако, в управляемом приложении 1С:Предприятия 8.3, особенно при работе в веб-клиенте или тонком клиенте, использование модальных окон, таких как те, что создаются функцией ВвестиСтроку, крайне не рекомендуется. Они могут приводить к блокировке интерфейса, некорректной работе и ухудшению пользовательского опыта.
  4. Безопасность хранения пароля: Хранение пароля в открытом виде непосредственно в коде (например, "Любой") крайне небезопасно и неприемлемо для реальных систем. Мы должны всегда использовать более защищенные методы хранения и проверки паролей.

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

2. Современные и оптимальные подходы (немодальные окна и механизмы платформы)

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

2.1. Использование отдельной управляемой формы для ввода пароля

Оптимальное решение для запроса пароля, соответствующее рекомендациям по разработке на управляемых формах, предполагает создание отдельной формы для ввода пароля. Эта форма будет вызываться немодально, а результат ее работы будет обрабатываться через механизм оповещений.

Разберем по шагам, как мы можем реализовать этот подход:

  1. Создаем общую управляемую форму для ввода пароля:
    • В конфигурации создаем новую Общую управляемую форму (например, "ФормаВводаПароля").
    • На эту форму помещаем поле ввода (тип: Строка). Для этого поля устанавливаем свойство РежимПароля = Истина, чтобы символы отображались звездочками.
    • Добавляем кнопки "ОК" (с командой, которая закрывает форму, передавая введенный пароль) и "Отмена" (просто закрывает форму).
    • В модуле этой формы реализуем функцию, которая будет возвращать введенный пароль или пустую строку при отмене.

    Пример кода для модуля формы "ФормаВводаПароля":

    
    // В МодулеОбъекта формы "ФормаВводаПароля" (если нужна логика возврата)
    // Или в МодулеФормы, если просто передаем параметр при закрытии
    
    &НаКлиенте
    Перем мВведенныйПароль;
    
    &НаКлиенте
    Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
        // Инициализация формы, если необходимо
        // Например, установка заголовка
        ЭтаФорма.Заголовок = "Введите пароль";
        мВведенныйПароль = ""; // Обнуляем на всякий случай
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ВвестиПарольНажатие(Команда)
        // Команда для кнопки "ОК"
        Если НЕ ЗначениеЗаполнено(Элементы.ПолеПароля.Значение) Тогда
            ПоказатьПредупреждение(,"Пароль не может быть пустым!");
            Возврат;
        КонецЕсли;
        мВведенныйПароль = Элементы.ПолеПароля.Значение;
        Закрыть(мВведенныйПароль); // Закрываем форму и передаем пароль
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ОтменаНажатие(Команда)
        // Команда для кнопки "Отмена"
        Закрыть(""); // Закрываем форму и передаем пустую строку
    КонецПроцедуры
    
  2. Вызываем форму ввода пароля:

    Мы будем вызывать эту форму в процедуре ПередОткрытием формы документа, которую хотим защитить. Вместо ВвестиСтроку, мы используем ОткрытьФорму() с параметром оповещения, чтобы обработать результат после закрытия формы пароля.

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

Этот подход более сложен в реализации, но он соответствует лучшим практикам 1С для управляемых форм, обеспечивает гибкость и избегает проблем с модальностью.

2.2. Централизованная обработка через подписку на событие

Если нам нужно применить механизм запроса пароля ко многим документам или объектам, то реализация кода в каждом модуле формы становится неэффективной и неудобной. В этом случае мы можем использовать механизм подписок на события. Этот подход позволяет централизовать логику, упростить поддержку и расширение.

Мы можем создать подписку на событие ОбработкаПолученияФормы для всех необходимых объектов. Это событие возникает до того, как система получит и отобразит форму объекта.

Разберем, как это можно сделать:

  1. Создаем подписку на событие:
    • В конфигурации создаем новый объект "Подписка на событие".
    • Указываем Источник: выбираем все документы, для которых нужна защита, или общий тип (например, "ДокументОбъект").
    • Указываем Событие: ОбработкаПолученияФормы.
    • Указываем Обработчик: создаем новую Общую серверную процедуру (например, в ОбщемМодуле).
  2. Реализуем логику в обработчике подписки:

    В обработчике подписки мы можем перехватить запрос на получение формы и, при необходимости, заменить ее на форму ввода пароля или выполнить проверку.

    
    // В ОбщемМодуле (серверный модуль)
    
    Процедура МояПодпискаНаОбработкуПолученияФормы(ИмяФормы, Параметры, СтандартнаяОбработка, ИмяОбъектаКонфигурации) Экспорт
        // Здесь мы можем решить, для каких форм нужна защита.
        // Например, защитим только форму документа "РасходнаяНакладная".
        Если ИмяОбъектаКонфигурации = "Документ.РасходнаяНакладная" И НЕ ПолучитьТекущийПользовательАутентифицированНаПароль() Тогда // Пример условия
            // Отменяем стандартную обработку получения формы документа
            СтандартнаяОбработка = Ложь; 
                    
            // Передаем параметры для открытия формы пароля и информации о том, какую форму нужно открыть потом
            ПараметрыДляФормыПароля = Новый Структура;
            ПараметрыДляФормыПароля.Вставить("ИмяЗапрашиваемойФормы", ИмяФормы);
            ПараметрыДляФормыПароля.Вставить("ПараметрыЗапрашиваемойФормы", Параметры);
            ПараметрыДляФормыПароля.Вставить("ИмяОбъектаКонфигурации", ИмяОбъектаКонфигурации);
    
            // Запускаем открытие формы пароля (функция должна быть клиентской)
            ОткрытьФормуВводаПароляНаКлиенте(ПараметрыДляФормыПароля);
        КонецЕсли;
    КонецПроцедуры
    
    // В ОбщемМодуле (клиентский модуль, или отдельный клиентский общий модуль)
    &НаКлиенте
    Процедура ОткрытьФормуВводаПароляНаКлиенте(ПараметрыОткрытия) Экспорт
        ОткрытьФорму("ОбщаяФорма.ФормаВводаПароля", ПараметрыОткрытия, , , , , , Новый ОписаниеОповещения("ПослеВводаПароляИзПодписки", ЭтотОбъект));
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ПослеВводаПароляИзПодписки(ПарольВведен, ДополнительныеПараметры) Экспорт
        Если ТипЗнч(ПарольВведен) = Тип("Строка") И НЕ ПустаяСтрока(ПарольВведен) Тогда
            Если ПарольВведен = "Любой" Тогда // Проверка пароля
                // Если пароль верен, открываем исходную форму
                ОткрытьФорму(ДополнительныеПараметры.ИмяЗапрашиваемойФормы, ДополнительныеПараметры.ПараметрыЗапрашиваемойФормы);
            Иначе
                // Пароль неверный
                ПоказатьПредупреждение(,"Неправильный пароль! Документ не будет открыт.");
            КонецЕсли;
        Иначе
            ПоказатьПредупреждение(,"Открытие документа отменено пользователем.");
        КонецЕсли;
    КонецПроцедуры
    
    // В ОбщемМодуле (серверный или клиент-серверный модуль)
    // Пример функции для демонстрации, в реальной системе должна быть проверка прав.
    Функция ПолучитьТекущийПользовательАутентифицированНаПароль()
        Возврат Ложь; // Предполагаем, что пока не аутентифицирован
    КонецФункции
    

Этот подход более элегантен и гибок, когда требуется централизованное управление логикой открытия форм.

2.3. Использование встроенных механизмов безопасности 1С (Роли, RLS)

Перед тем как разрабатывать собственный механизм парольной защиты на каждый документ, мы должны серьезно рассмотреть использование стандартных средств безопасности платформы 1С. Зачастую, такая "парольная защита" является избыточной или неправильно реализует требования, которые уже покрыты платформой.

Мы предлагаем обратить внимание на следующие возможности:

  1. Роли и права доступа:

    Основной механизм разграничения доступа в 1С. Мы можем создать различные роли, которые будут давать или не давать право на чтение, изменение, добавление или просмотр форм определенных видов документов. Например, если только бухгалтер должен видеть "Расходные накладные", мы создаем роль "Бухгалтер" и даем ей соответствующие права, а другим ролям не даем. Доступ к системе осуществляется по имени пользователя и его паролю, установленному средствами 1С.

    Это самый оптимальный и безопасный подход для большинства случаев, так как он встроен в платформу и обеспечивает комплексную защиту на уровне данных.

  2. Row-Level Security (RLS):

    Если нам нужна более гранулированная защита, например, когда один менеджер должен видеть только "свои" расходные накладные, а другой - "свои", мы используем RLS. RLS позволяет настроить правила на уровне записей данных, определяя, какие именно записи (документы, элементы справочников) доступны для просмотра, изменения или удаления конкретным пользователям или группам доступа.

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

Использование ролей и RLS — это предпочтительный путь для реализации требований безопасности в 1С. Если требование "пароль на документ" является лишь способом ограничить доступ, то, вероятно, эти механизмы будут более эффективными и безопасными.

2.4. Хранение и проверка паролей

Если, несмотря на все рекомендации, мы все же решаем реализовать собственный механизм парольной защиты, критически важно продумать вопросы безопасности хранения и проверки паролей. Хранение паролей в открытом виде (как "Любой" в нашем первом примере) категорически неприемлемо.

Рассмотрим основные принципы:

  1. Хеширование паролей:

    Пароли должны храниться в базе данных не в открытом виде, а в виде хешей. Хеш — это результат одностороннего преобразования пароля с использованием криптографической хеш-функции. При проверке введенный пользователем пароль также хешируется, и его хеш сравнивается с сохраненным хешем. Если хеши совпадают, пароль верен.

    В 1С для этих целей можно использовать функции платформы, например, из модуля ОбщегоНазначенияКлиентСервер или МенеджерКриптографии, если требуется более стойкое хеширование. Например, можно использовать MD5 или SHA-256 (хотя MD5 уже считается устаревшим для паролей). Применение "соли" (случайной строки, добавляемой к паролю перед хешированием) еще больше повышает безопасность.

    Пример (концептуальный) хеширования пароля с "солью":

    
    // Функция для хеширования пароля (пример)
    Функция ПолучитьХешПароля(Пароль, Соль)
        Хешировщик = Новый ХешированиеДанных(ВидХешФункции.SHA256);
        ХешСтрока = Хешировщик.ХешироватьСтроку(Пароль + Соль);
        Возврат ХешСтрока;
    КонецФункции
    
    // Пример использования
    СохраненныйПарольХеш = "ВашХешПароляИзБазы"; // Полученный ранее хеш
    СохраненнаяСоль = "ВашаСольИзБазы";       // Полученная ранее соль
            
    ВведенныйПароль = "Любой"; // Пароль, который ввел пользователь
    ХешВведенногоПароля = ПолучитьХешПароля(ВведенныйПароль, СохраненнаяСоль);
    
    Если ХешВведенногоПароля = СохраненныйПарольХеш Тогда
        // Пароль верен
    Иначе
        // Пароль не верен
    КонецЕсли;
    
  2. Хранение хешей и солей:

    Хеши паролей и соответствующие им "соли" следует хранить в отдельных, защищенных регистрах сведений или реквизитах объектов, к которым имеют доступ только пользователи с соответствующими правами. Никогда не храните соль в коде, она должна быть уникальной для каждого пароля и храниться вместе с хешем.

  3. Управление паролями:

    Мы также должны продумать механизм установки и смены паролей для документов. Кто будет иметь право устанавливать или сбрасывать эти пароли? Это может быть реализовано через отдельную форму настройки или функционал документа, доступный только определенным ролям.

Заключение

Мы рассмотрели различные подходы к реализации запроса пароля при открытии документа в 1С:Предприятии 8.3. Если перед нами стоит задача простого "тестового задания" без глубоких требований к безопасности и масштабируемости, то решение с использованием ВвестиСтроку в ПередОткрытием может быть приемлемым, но мы помним о его недостатках.

Для реальных систем мы всегда будем стремиться к более современным и безопасным методам:

  1. Использовать отдельные управляемые формы для ввода пароля с асинхронными вызовами, чтобы избежать модальных окон.
  2. Применять подписки на события для централизованного управления логикой, если требуется защитить множество объектов.
  3. В первую очередь рассматривать встроенные механизмы безопасности 1С (роли, RLS), так как они являются наиболее надежным и гибким решением для разграничения доступа.
  4. И, конечно, всегда обеспечивать безопасность хранения паролей, используя хеширование и "соли".

Выбор оптимального решения всегда зависит от конкретных требований проекта, уровня необходимой безопасности и предполагаемой нагрузки на систему. Мы рекомендуем отдавать предпочтение встроенным механизмам платформы и современным принципам разработки управляемого приложения.

← На главную