Проверка личности
Узнавайте вошедшего человека и восстанавливайте историю его диалогов на разных устройствах, используя подпись, которой управляет ваш backend.
Зачем проверять#
По умолчанию SDK анонимен: он генерирует стабильный visitor_id и держит его в платформенном keystore. Этого достаточно для одного диалога на одном устройстве. Чтобы узнать конкретного пользователя, восстановить историю при повторном входе или на другом устройстве и надёжно привязать диалог к профилю контакта, backend нужно доказательство, что клиент — тот, за кого себя выдаёт. Если бы SDK просто отправлял «я пользователь 42», любой мог бы подделать чужой id и прочитать чужой чат — поэтому Respondo требует криптографическую подпись, userHash, которую может создать только ваш backend.
Получение identity secret#
identity_secret — это секретная строка, привязанная к вашему агенту (ИИ-работнику, к которому подключён канал вашего виджета). Сгенерируйте его в панели управления: Каналы → Виджет → Проверка личности. Секрет лежит на агенте, поэтому он общий для всех каналов этого агента — и веб-виджета, и мобильного SDK. Он даёт право подписывать личности, поэтому должен жить только на вашем backend и никогда не поставляться в приложении.
Формула userHash#
userHash — это HMAC-SHA256 над единственной подписываемой строкой личности, закодированный как hex в нижнем регистре:
userHash = HMAC_SHA256( identity_secret, payload )
payload = userId // если userId задан
= email // иначе, если задан email
= (invalid) // если оба пусты, подписывать нечего- Секрет — это ключ HMAC; строка личности — это сообщение, а не наоборот.
- Подписывайте ровно одну строку — сырой
userId(или email), без соли и JSON-обёртки. - Если вы передаёте и
userId, и email, подписывайтеuserId(у него приоритет). - Вывод — hex (64 символа для SHA-256), не base64.
Примеры для backend#
Вычислите подпись на своём backend и передайте готовый userHash в приложение.
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)
// HMAC_SHA256(identity_secret, userId) как hex в нижнем регистре.
func ComputeUserHash(identitySecret, userID string) string {
mac := hmac.New(sha256.New, []byte(identitySecret))
mac.Write([]byte(userID))
return hex.EncodeToString(mac.Sum(nil))
}const crypto = require("crypto");
// Возвращает userHash для передачи в Respondo.identify на мобильном клиенте.
function computeUserHash(identitySecret, userId) {
return crypto
.createHmac("sha256", identitySecret)
.update(userId, "utf8")
.digest("hex");
}import hmac
import hashlib
# Возвращает userHash для передачи в Respondo.identify на мобильном клиенте.
def compute_user_hash(identity_secret: str, user_id: str) -> str:
return hmac.new(
identity_secret.encode(),
user_id.encode(),
hashlib.sha256,
).hexdigest()<?php
// Возвращает userHash для передачи в Respondo.identify на мобильном клиенте.
function computeUserHash(string $identitySecret, string $userId): string {
return hash_hmac('sha256', $userId, $identitySecret);
}Как хэш попадает в Respondo#
/identity не существует и регистрировать ничего не нужно. userHash — это поле, которое едет в запросах, что SDK и так делает.Два хопа, и строите вы только первый:
- Ваш backend → ваше приложение. Доставляете хэш как удобно. Дешевле всего — дополнительным полем в ответе логина/бутстрапа, который вы и так отдаёте (лишнего запроса нет). Отдельная ручка на вашем собственном backend (например
POST /myapp/identity→{ userId, userHash }) работает не хуже. Respondo эту ручку не предоставляет — её пишете вы. - Ваше приложение → Respondo. Делает SDK. После вызова
identifyхэш сам прикладывается к нужным запросам, а backend перепроверяет подпись на каждом.
POST /api/v1/chat body identity.userHash
GET /api/v1/chat/resume query user_hash
GET /api/v1/chat/history query user_hash
GET /api/v1/chat/ws frames user_hash (JSON-фреймы subscribe/identify после подключения — не в URL хендшейка)
GET /api/v1/widget/tours query user_hash
GET /api/v1/widget/checklists query user_hash
POST /api/v1/widget/push/register body user_hashПодпись перепроверяется на каждом запросе, а не обменивается один раз на сессию — именно поэтому украденный userId сам по себе бесполезен.
identify не вызовется, и чат поедет анонимно. Это ожидаемое поведение, а не ошибка Respondo: 404 на вашем собственном пути — задача на вашей стороне, а не сломанная интеграция.Передача личности в SDK#
Получите подписанную личность со своего backend, затем передайте userHash в identify на любой платформе:
Respondo.identify(
RespondoIdentity(userId = "42", email = "user@example.com", userHash = hash),
)Respondo.identify(
RespondoIdentity(userId: "42", email: "user@example.com", userHash: hash)
)Respondo.identify(RespondoIdentity(
userId: '42', email: 'user@example.com', userHash: hash,
));Поведение при неверном userHash#
Когда проверка включена у агента, а подпись отсутствует или неверна, backend выполняет тихое понижение до анонима: чат по-прежнему работает, visitor_id сохраняется, а диалог привязывается к анонимному контакту — но без связи с профилем и без кросс-девайс-истории. Если пользователь «не узнаётся», почти всегда дело в подписи: проверьте, что вы подписали userId (не email и не JSON), использовали правильный identity_secret и выдали hex в нижнем регистре. Если identity_secret агента пуст, проверка выключена, и userId / email принимаются как есть.
Ротация identity_secret — это, по сути, жёсткое переключение: каждый хеш, созданный со старым секретом, тут же перестаёт проходить проверку, поэтому уже вошедшие пользователи молча откатываются до анонима, пока ваш backend не пересчитает и не переподаст их userHash с новым секретом. Меняйте секрет только тогда, когда можете обновить подписывающую сторону в том же окне.