В процессе администрирования и разработки на платформе 1С:Предприятие часто возникает задача ограничить количество активных сеансов для одного пользователя. Это может быть связано с требованиями безопасности, политикой лицензирования (особенно в веб-клиенте, где каждый сеанс потребляет лицензию) или необходимостью предотвратить коллизии при записи данных. Разберем подробно, почему стандартные методы для тонкого клиента не всегда работают в вебе и как правильно реализовать проверку.
Проанализируем ситуацию: стандартный подход, который часто используют разработчики, базируется на функции ПолучитьСоединенияИнформационнойБазы(). В тонком клиенте этот метод работает корректно, так как каждое запущенное приложение создает прямое соединение с сервером. Однако при работе через веб-сервер (IIS или Apache) ситуация меняется.
Выясним причину: веб-сервер использует так называемый пул соединений. С точки зрения платформы 1С, веб-сервер может держать всего одно или несколько физических соединений, внутри которых мультиплексируются запросы десятков различных пользователей. Поэтому метод ПолучитьСоединенияИнформационнойБазы() в веб-клиенте часто возвращает только одно соединение (самого веб-сервера), «не замечая» другие открытые вкладки браузера того же пользователя.
Для решения задачи в веб-клиенте мы должны использовать другой механизм. Рассмотрим объект СеансИнформационнойБазы. Именно сеанс представляет собой логическую сессию работы пользователя с базой данных, которая сохраняется между запросами браузера. Чтобы получить список всех активных пользователей, включая тех, кто зашел через веб, нам понадобится метод ПолучитьСеансыИнформационнойБазы().
Посмотрим на пример логики, которую следует разместить в модуле управляемого приложения в процедуре ПриНачалеРаботыСистемы:
Процедура ПриНачалеРаботыСистемы()
#Если Клиент Тогда
Если ПовторныйВходЗапрещен() Тогда
ПоказатьПредупреждение(, "Вы уже вошли в систему под этим именем. Второй сеанс запрещен.");
ЗавершитьРаботуСистемы(Ложь);
КонецЕсли;
#КонецЕсли
КонецПроцедуры
Теперь разберем по шагам, как должна выглядеть функция проверки на стороне сервера. Нам важно отсечь текущий сеанс, чтобы система не блокировала сама себя, а также игнорировать фоновые задания и сеансы конфигуратора.
Функция ПовторныйВходЗапрещен() Экспорт
ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы();
ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
МассивСеансов = ПолучитьСеансыИнформационнойБазы();
КоличествоСеансов = 0;
Для Каждого Сеанс Из МассивСеансов Цикл
// Проверяем, что это тот же пользователь
Если Сеанс.Пользователь.УникальныйИдентификатор = ТекущийПользователь.УникальныйИдентификатор Тогда
// Исключаем текущий сеанс из подсчета
Если Сеанс.НомерСеанса <> ТекущийСеанс.НомерСеанса Тогда
// Проверяем тип приложения, чтобы не блокировать вход,
// если открыт Конфигуратор или выполняется фоновое задание
ИмяПриложения = Сеанс.ИмяПриложения;
Если ИмяПриложения = "1CV8" ИЛИ ИмяПриложения = "WebClient" Тогда
КоличествоСеансов = КоличествоСеансов + 1;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат КоличествоСеансов > 0;
КонецФункции
Проанализируем важный нюанс: в веб-клиенте пользователь часто завершает работу, просто закрывая вкладку браузера или закрывая ноутбук. В этом случае сеанс на сервере 1С не завершается мгновенно. Он переходит в состояние «спящего» и может удерживать лицензию и блокировать новый вход еще 20 минут (стандартный таймаут платформы).
Рассмотрим два варианта решения этой проблемы:
Для программного завершения сеанса нам потребуется использовать методы административного интерфейса. Выясним, как это реализовать. Обратите внимание, что для выполнения этой операции у текущего пользователя или у сервера должны быть соответствующие права (или код должен выполняться в привилегированном режиме).
Процедура ВытеснитьПредыдущиеСеансы() Экспорт
ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы();
ПользовательИмя = ПользователиИнформационнойБазы.ТекущийПользователь().Имя;
Сеансы = ПолучитьСеансыИнформационнойБазы();
Для Каждого СтрСеанс Из Сеансы Цикл
Если СтрСеанс.Пользователь.Имя = ПользовательИмя
И СтрСеанс.НомерСеанса <> ТекущийСеанс.НомерСеанса Тогда
Попытка
Менеджер = СоединенияИнформационнойБазы.ПолучитьСоединения();
// Здесь логика завершения через внешнее соединение или COM-администрирование
// В новых версиях платформы рекомендуется использовать методы БСП
Исключение
// Запись в журнал регистрации об ошибке доступа
КонецПопытки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Если ваша конфигурация построена на базе БСП, мы настоятельно рекомендуем использовать штатные механизмы. В подсистеме Пользователи уже реализованы механизмы мониторинга активности. В частности, можно воспользоваться функционалом «Параметры работы пользователей», где в последних версиях платформы и БСП предусмотрены настройки ограничения количества одновременных входов. Это позволит избежать написания сложного кода «с нуля» и обеспечит стабильную работу системы как в тонком, так и в веб-клиенте.
Важный совет: Прежде чем внедрять жесткую блокировку, обучите пользователей правильно выходить из системы в веб-клиенте — через кнопку «Завершить работу», а не просто закрывая браузер. Это значительно сократит количество обращений в техподдержку по поводу «ложных» блокировок.