תיעוד

אימות זהות

זהו אדם מחובר ושחזרו את היסטוריית השיחות שלו בין מכשירים, באמצעות חתימה שה-backend שלכם שולט בה.

למה לאמת#

כברירת מחדל ה-SDK אנונימי: הוא מייצר visitor_id יציב ושומר אותו ב-keystore של הפלטפורמה. זה מספיק לשיחה אחת במכשיר אחד. כדי לזהות משתמש מסוים, לשחזר היסטוריה בהתחברות מחדש או במכשיר אחר, ולקשור באופן אמין שיחה לפרופיל איש קשר, ה-backend צריך הוכחה שהלקוח הוא מי שהוא טוען שהוא. אם ה-SDK פשוט היה שולח "אני משתמש 42", כל אחד יכול היה להתחזות למזהה אחר ולקרוא צ׳אט של מישהו אחר — ולכן Respondo דורש חתימה קריפטוגרפית, userHash, שרק ה-backend שלכם יכול לייצר.

קבלת סוד הזהות#

ה-identity_secret הוא מחרוזת סודית הקשורה לסוכן שלכם (עובד ה-AI שאליו מחובר ערוץ הווידג׳ט שלכם). צרו אותו בלוח הבקרה תחת Channels → Widget → Identity verification. מכיוון שהוא יושב על הסוכן, כל ערוץ שמבוסס על אותו סוכן — גם וידג׳ט הווב וגם ה-SDK הנייד — חולק את אותו סוד. הוא מעניק את הזכות לחתום על זהויות, ולכן הוא חייב להתקיים רק ב-backend שלכם ולעולם אסור שיישלח באפליקציה.

נוסחת ה-userHash#

userHash הוא HMAC-SHA256 על מחרוזת זהות חתומה אחת, מקודד כ-hex באותיות קטנות:

נוסחהtext
userHash = HMAC_SHA256( identity_secret, payload )

payload = userId          // אם userId מוגדר
        = email           // אחרת, אם email מוגדר
        = (invalid)       // אם שניהם ריקים, אין מה לחתום
  • הסוד הוא ה-מפתח של ה-HMAC; מחרוזת הזהות היא ה- הודעה — לא להפך.
  • חתמו על מחרוזת אחת בדיוק — ה- userId הגולמי (או האימייל), ללא salt וללא עטיפת JSON.
  • אם אתם מעבירים גם userId וגם email, חתמו על ה-userId (יש לו עדיפות).
  • הפלט הוא hex (64 תווים עבור SHA-256), לא base64.

דוגמאות צד שרת#

חשבו את החתימה ב-backend שלכם ומסרו את ה- userHash המוכן לאפליקציה.

Gogo
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))
}
Node.jsjavascript
const crypto = require("crypto");

// מחזירה את ה-userHash שיש להעביר ל-Respondo.identify בלקוח הנייד.
function computeUserHash(identitySecret, userId) {
  return crypto
    .createHmac("sha256", identitySecret)
    .update(userId, "utf8")
    .digest("hex");
}
Pythonpython
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()
PHPphp
<?php
// מחזירה את ה-userHash שיש להעביר ל-Respondo.identify בלקוח הנייד.
function computeUserHash(string $identitySecret, string $userId): string {
    return hash_hmac('sha256', $userId, $identitySecret);
}

כיצד ה-hash מגיע ל-Respondo#

ל-Respondo אין endpoint ייעודי לזהות. אין נתיב /identity שצריך לקרוא לו ואין מה לרשום. userHash הוא שדה שנוסע בתוך הבקשות שה-SDK כבר שולח.

שני מקטעים, ורק הראשון הוא באחריותכם לבנות:

  1. ה-backend שלכם → האפליקציה שלכם. אתם מוסרים את ה-hash בכל דרך שנוחה לכם. הזול ביותר הוא שדה נוסף בתשובת ההתחברות/האתחול שאתם ממילא מחזירים — בלי סבב בקשות נוסף. endpoint ייעודי ב-backend שלכם (למשל POST /myapp/identity שמחזיר { userId, userHash }) עובד באותה מידה. Respondo לא מארחת את ה-endpoint הזה — אתם מממשים אותו.
  2. האפליקציה שלכם → Respondo. מטופל עבורכם. ברגע שאתם קוראים ל-identify, ה-SDK מצרף את ה-hash לכל בקשה רלוונטית וה-backend מאמת אותו מחדש בכל פעם.
היכן ה-SDK מציב אותו (לעיון — אינכם שולחים את אלה ידנית)text
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 (subscribe/identify JSON frames after connect — not in the handshake 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

ה-hash נבדק מחדש בכל בקשה, ולא מוחלף פעם אחת עבור סשן שלם — בדיוק זה מה שהופך userId גנוב לחסר תועלת בפני עצמו.

אם ה-endpoint למסירה ב-backend שלכם עדיין לא נבנה, הבקשה של האפליקציה שלכם עצמה מחזירה 404, identify לעולם לא נקרא, והצ׳אט רץ אנונימית. זו התנהגות צפויה ולא שגיאה של Respondo — 404 בנתיב שלכם הוא משימה פתוחה בצד שלכם, לא אינטגרציה שבורה.

העברת הזהות ל-SDK#

משכו את הזהות החתומה מה-backend שלכם, ואז העבירו את ה- userHash אל identify בכל פלטפורמה:

Kotlinkotlin
Respondo.identify(
    RespondoIdentity(userId = "42", email = "user@example.com", userHash = hash),
)
Swiftswift
Respondo.identify(
    RespondoIdentity(userId: "42", email: "user@example.com", userHash: hash)
)
Dartdart
Respondo.identify(RespondoIdentity(
  userId: '42', email: 'user@example.com', userHash: hash,
));

התנהגות עם userHash שגוי#

כאשר האימות מופעל על הסוכן והחתימה חסרה או שגויה, ה-backend מבצע הורדה שקטה למצב אנונימי: הצ׳אט עדיין עובד, ה- visitor_id נשמר, והשיחה נקשרת לאיש הקשר האנונימי — אך אין קישור לפרופיל ואין היסטוריה חוצה-מכשירית. אם משתמש "אינו מזוהה", כמעט תמיד מדובר בחתימה: בדקו שחתמתם על ה- userId (לא אימייל או JSON), השתמשתם ב- identity_secret הנכון, והפקתם hex באותיות קטנות. אם ה- identity_secret של הסוכן ריק, האימות כבוי ו- userId / אימייל מתקבלים כמות שהם.

החלפת ה- identity_secret היא למעשה מעבר חד: כל hash שהופק עם הסוד הישן מפסיק להתאמת מיידית, כך שמשתמשים שכבר מחוברים נופלים בשקט למצב אנונימי עד שה-backend שלכם מחשב מחדש ומספק שוב את ה- userHash שלהם עם הסוד החדש. החליפו את הסוד רק כאשר תוכלו לעדכן את צד החתימה באותו חלון זמן.