В практике интеграции 1С:Предприятия с внешними порталами, CRM-системами или корпоративными сайтами часто возникает задача управления сеансами пользователей. Одна из таких задач — корректное завершение сеанса 1С (logout) по команде из внешней системы. Для этого часто используется специальная ссылка, содержащая параметр seanceId. Однако этот параметр не является статичным и простым идентификатором, который можно получить из стандартных свойств глобального контекста.
Разберем детально проблему, почему стандартный GUID сеанса не подходит, и рассмотрим рабочий технический прием ("хак"), позволяющий извлечь актуальный подписанный токен сеанса непосредственно из кода встроенного языка 1С, а также обсудим альтернативные серверные подходы.
Стандартная ссылка для выхода из веб-клиента выглядит следующим образом:
https://адрес_сервера/база/ru/e1cib/logout?seanceId=...&beaconAPI=true
Многие разработчики ошибочно полагают, что параметр seanceId равен значению, возвращаемому методом УникальныйИдентификатор() текущего сеанса. Это не так. Давайте проанализируем, что представляет собой этот параметр.
Следовательно, просто взять и "угадать" или вычислить его из базы данных невозможно. Нам нужно заставить платформу саму отдать нам этот токен.
Наиболее эффективный способ получить актуальный seanceId на клиенте (в веб-клиенте) — использовать особенности работы механизма временного хранилища.
Когда мы помещаем любые данные во временное хранилище, платформа возвращает нам навигационную ссылку (адрес). Поскольку веб-клиент работает через HTTP, этот адрес должен быть доступен браузеру для скачивания или загрузки файлов. Чтобы сервер понял, к какому сеансу относится запрос на получение данных из хранилища, платформа автоматически добавляет параметр seanceId в конец URL-адреса этого хранилища.
Давайте рассмотрим алгоритм действий, который позволяет извлечь этот идентификатор.
Шаг 1. Помещение данных в хранилище
Нам не важно, что именно помещать. Можно поместить Неопределено или пустую строку. Главное — получить адрес. Эту операцию можно выполнить как на сервере, так и на клиенте (если доступен метод), но анализ строки проще всего делать на клиенте, так как именно там формируется окончательный URL для браузера.
Шаг 2. Анализ полученного адреса
Полученная ссылка будет иметь примерно следующий вид:
e1cib/tempstorage/675915e6-7a72-4735-a691-3a98893193cf?seanceId=NWQ0ZDNhODQtZjY0OS00N2ZjLWI3ZjUtMDk4YzRhZjQ2Nzc1NHbDnvZQJkamwgWK8FusyAAAAAA
Как мы видим, искомое значение находится в явном виде после параметра ?seanceId=.
Шаг 3. Реализация функции получения ID
Напишем функцию на встроенном языке 1С, которую можно использовать в модулях управляемого приложения или общих модулях с контекстом клиента.
&НаКлиенте
Функция ПолучитьТекущийSeanceId() Экспорт
// 1. Помещаем пустое значение во временное хранилище.
// УникальныйИдентификатор (второй параметр) нужен для привязки к форме,
// но для простого получения адреса можно передать Новый УникальныйИдентификатор
АдресХранилища = ПоместитьВоВременноеХранилище(Неопределено, Новый УникальныйИдентификатор);
// 2. АдресХранилища содержит строку вида "e1cib/tempstorage/GUID?seanceId=TOKEN"
// Нам нужно найти начало параметра seanceId
ПоисковаяСтрока = "seanceId=";
ПозицияПараметра = СтрНайти(АдресХранилища, ПоисковаяСтрока);
Если ПозицияПараметра = 0 Тогда
// Если параметра нет, возможно, мы не в веб-клиенте или формат URL изменился
Возврат "";
КонецЕсли;
// 3. Вычисляем начало самого токена
НачалоТокена = ПозицияПараметра + СтрДлина(ПоисковаяСтрока);
// 4. Извлекаем подстроку до конца строки (обычно seanceId идет последним параметром)
// Если есть другие параметры (через &), нужно будет доработать парсинг
ТекущийSeanceId = Сред(АдресХранилища, НачалоТокена);
// Очищаем хвост, если вдруг там есть другие параметры (например &beaconAPI=true)
ПозицияАмперсанда = СтрНайти(ТекущийSeanceId, "&");
Если ПозицияАмперсанда > 0 Тогда
ТекущийSeanceId = Лев(ТекущийSeanceId, ПозицияАмперсанда - 1);
КонецЕсли;
Возврат ТекущийSeanceId;
КонецФункции
Теперь, имея этот токен, мы можем сформировать корректную ссылку для выхода и передать её во внешнюю CRM-систему или открыть в браузере.
&НаКлиенте
Процедура СформироватьСсылкуВыхода()
ИдСеанса = ПолучитьТекущийSeanceId();
Если ЗначениеЗаполнено(ИдСеанса) Тогда
// Получаем базовый адрес (например, https://server/base/)
// В реальном приложении адрес лучше получать динамически или хранить в константах
БазовыйАдрес = "https://my-server.com/base/";
СсылкаLogOut = БазовыйАдрес + "ru/e1cib/logout?seanceId=" + ИдСеанса;
// Передаем ссылку во внешнюю систему или используем ПереходПоНавигационнойСсылке
Сообщить("Ссылка для выхода: " + СсылкаLogOut);
Иначе
Сообщить("Не удалось получить идентификатор сеанса. Возможно, запуск не в веб-клиенте.");
КонецЕсли;
КонецПроцедуры
Используя данный подход, необходимо учитывать несколько нюансов:
e1cib там работает внутри протокола TCP/HTTP, но визуальное представление адреса может отличаться или не содержать явного seanceId, так как авторизация проходит иначе).seanceId или передаваться в URL. Это классический пример использования недокументированных возможностей.Если задача состоит в том, чтобы внешняя CRM-система могла "выкинуть" пользователя из 1С, и при этом у вас есть доступ к администрированию сервера 1С, рассмотрим более надежный, "правильный" архитектурный подход.
Вместо того чтобы заставлять браузер пользователя переходить по ссылке logout, CRM-система может отправить запрос на свой бэкенд, который, в свою очередь, свяжется с сервером 1С и принудительно завершит сеанс.
Для этого можно использовать COM-соединение (V83.ComConnector) к рабочему процессу или Administration API (RAS/RAC).
Пример логики через COM-соединение (выполняется на стороне сервера, имеющего доступ к агенту сервера 1С):
// Пример на встроенном языке 1С (запуск в привилегированном режиме)
// Требует права администрирования
Функция УдалитьСеансПользователя(ИмяПользователя) Экспорт
Соединитель = Новый COMОбъект("V83.ComConnector");
// Подключаемся к агенту сервера (не к базе данных!)
Агент = Соединитель.ConnectAgent("ИмяСервера1С");
Кластеры = Агент.GetClusters();
Для Каждого Кластер Из Кластеры Цикл
Агент.Authenticate(Кластер, "АдминистраторКластера", "Пароль");
Сеансы = Агент.GetSessions(Кластер);
Для Каждого Сеанс Из Сеансы Цикл
// Проверяем имя пользователя и базу данных
Если Сеанс.UserName = ИмяПользователя И Сеанс.InfoBase.Name = "ИмяБазы" Тогда
// Принудительное завершение
Агент.TerminateSession(Кластер, Сеанс);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецФункции
Преимущества серверного метода:
Для решения задачи получения seanceId в веб-клиенте "здесь и сейчас" метод с парсингом адреса временного хранилища является рабочим и эффективным. Он позволяет сформировать ссылку выхода, которая корректно завершит работу веб-приложения.
Однако при проектировании долгосрочных корпоративных решений рекомендуется рассмотреть использование серверного API администрирования или переход на стандартизированные протоколы аутентификации, такие как OpenID Connect. В случае с OpenID выход осуществляется через редирект на Identity Provider (механизм End-Session Endpoint), что избавляет от необходимости манипулировать внутренними идентификаторами 1С.