אימות בקשות מ-Google Chat

באפליקציות של Google Chat שמבוססות על נקודות קצה ב-HTTP, מוסבר כאן איך לוודא שהבקשות לנקודת הקצה שלכם מגיעות מ-Chat.

כדי לשלוח אירועי אינטראקציה לאפליקציית Chat נקודת הקצה, Google שולחת בקשות לשירות שלך. כדי לוודא שהבקשה שמגיע מ-Google, אסימון למוכ"ז בכותרת Authorization של כל בקשת HTTPS לנקודת הקצה. לדוגמה:

POST
Host: yourappurl.com
Authorization: Bearer AbCdEf123456
Content-Type: application/json
User-Agent: Google-Dynamite

המחרוזת AbCdEf123456 בדוגמה שלמעלה היא ההרשאה למוכ"ז ב-Assistant. זהו אסימון קריפטוגרפי ש-Google מפיקה. סוג הגורם האחראי ואת הערך של audience השדה תלוי בסוג קהל האימות שבחרתם איך מגדירים את אפליקציית Chat.

אם הטמעתם את אפליקציית Chat באמצעות Cloud פונקציות או Cloud Run, Cloud IAM מטפל באימות אסימונים באופן אוטומטי. שלך צריך רק להוסיף את חשבון השירות של Google Chat כ-invoker מורשה. אם באפליקציה שלך מוטמע שרת HTTP משלה, אפשר לאמת את האסימון למוכ"ז. באמצעות ספריית לקוח של Google API בקוד פתוח:

אם לא הצלחתם לאמת את האסימון באפליקציית Chat, השירות צריך להגיב לבקשה עם קוד תגובת HTTPS 401 (Unauthorized)

אימות בקשות באמצעות Cloud Functions או Cloud Run

אם לוגיקת הפונקציות מיושמת באמצעות Cloud Functions או Cloud Run, חייבים לבחור את האפשרות App URL בשדה Authentication Audience של אפליקציית Chat את הגדרת החיבור ולוודא כתובת ה-URL של האפליקציה שבתצורה תואמת לכתובת ה-URL של הפונקציה של Cloud Functions, או נקודת קצה (endpoint) של Cloud Run.

לאחר מכן, צריך לתת הרשאה לחשבון השירות של Google Chat chat@system.gserviceaccount.com כגורם מפעיל.

בשלבים הבאים מוסבר איך להשתמש ב-Cloud Functions (דור ראשון):

המסוף

אחרי פריסת הפונקציה ב-Google Cloud:

  1. במסוף Google Cloud, נכנסים לדף Cloud Functions:

    כניסה ל-Cloud Functions

  2. ברשימה Cloud Functions, לוחצים על תיבת הסימון שליד מותאמת אישית. (אין ללחוץ על הפונקציה עצמה).

  3. לוחצים על הרשאות בחלק העליון של המסך. החלונית Permissions נפתח.

  4. לוחצים על Add principal.

  5. בשדה New principals, מזינים chat@system.gserviceaccount.com.

  6. בוחרים את התפקיד Cloud Functions > Cloud Functions Invoker מ- בתפריט הנפתח Select a rol.

  7. לוחצים על שמירה.

gcloud

משתמשים בפקודה gcloud functions add-iam-policy-binding:

gcloud functions add-iam-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:chat@system.gserviceaccount.com' \
  --role='roles/cloudfunctions.invoker'

מחליפים את RECEIVING_FUNCTION בשם שלכם הפונקציה של אפליקציית Chat.

השלבים הבאים מסבירים איך להשתמש בשירותי Cloud Functions (דור שני) או Cloud Run:

המסוף

אחרי פריסת הפונקציה או השירות ב-Google Cloud:

  1. במסוף Google Cloud, נכנסים לדף Cloud Run:

    כניסה ל-Cloud Run

  2. ברשימת שירותי Cloud Run, לוחצים על תיבת הסימון שליד מותאמת אישית. (אין ללחוץ על הפונקציה עצמה).

  3. לוחצים על הרשאות בחלק העליון של המסך. החלונית Permissions נפתח.

  4. לוחצים על Add principal.

  5. בשדה New principals, מזינים chat@system.gserviceaccount.com.

  6. בוחרים את התפקיד Cloud Run > Cloud Run Invoker מ- בתפריט הנפתח Select a rol.

  7. לוחצים על שמירה.

gcloud

משתמשים בפקודה gcloud functions add-invoker-policy-binding:

gcloud functions add-invoker-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:chat@system.gserviceaccount.com'

מחליפים את RECEIVING_FUNCTION בשם שלכם הפונקציה של אפליקציית Chat.

אימות בקשות באמצעות אסימון מזהה של כתובת URL של אפליקציה

אם השדה 'קהל לאימות' באפליקציית Chat הגדרת החיבור היא App URL, אסימון ההרשאה למוכ"ז בבקשה הוא OpenID Connect בחתימה של Google (OIDC) אסימון מזהה. השדה email מוגדר ל-chat@system.gserviceaccount.com. השדה audience מוגדר לכתובת ה-URL שהגדרת לשליחה ב-Google Chat בקשות לאפליקציית Chat שלך. לדוגמה, אם שנקודת הקצה שהוגדרה באפליקציית Chat היא https://example.com/app/, אז השדה audience באסימון המזהה הוא https://example.com/app/.

הדוגמאות הבאות מראות איך לאמת שאסימון למוכ"ז הונפק על ידי Google Chat וטירגוט לאפליקציה שלך באמצעות ספריית הלקוח של OAuth של Google.

Java

java/basic-app/src/main/java/com/google/chat/app/basic/App.java
String CHAT_ISSUER = "chat@system.gserviceaccount.com";
JsonFactory factory = JacksonFactory.getDefaultInstance();

GoogleIdTokenVerifier verifier =
    new GoogleIdTokenVerifier.Builder(new ApacheHttpTransport(), factory)
        .setAudience(Collections.singletonList(AUDIENCE))
        .build();

GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
return idToken != null
    && verifier.verify(idToken)
    && idToken.getPayload().getEmailVerified()
    && idToken.getPayload().getEmail().equals(CHAT_ISSUER);

Python

python/basic-app/main.py
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

try:
    # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
    request = requests.Request()
    token = id_token.verify_oauth2_token(bearer, request, AUDIENCE)
    return token['email'] == CHAT_ISSUER

except:
    return False

Node.js

node/basic-app/index.js
// Bearer Tokens received by apps will always specify this issuer.
const chatIssuer = 'chat@system.gserviceaccount.com';

// Verify valid token, signed by chatIssuer, intended for a third party.
try {
  const ticket = await client.verifyIdToken({
    idToken: bearer,
    audience: audience
  });
  return ticket.getPayload().email_verified
      && ticket.getPayload().email === chatIssuer;
} catch (unused) {
  return false;
}

אימות בקשות באמצעות JWT של מספר פרויקט

אם השדה 'קהל לאימות' באפליקציית Chat הגדרת החיבור מוגדרת ל-Project Number, אסימון ההרשאה למוכ"ז בבקשה הוא בחתימה עצמית אסימון אינטרנט מסוג JSON (JWT), הונפק ונחתם על ידי chat@system.gserviceaccount.com. השדה audience מוגדר למספר הפרויקט ב-Google Cloud שבו השתמשתם כדי לפתח את אפליקציית Chat. לדוגמה, אם מספר הפרויקט ב-Cloud של אפליקציית Chat הוא 1234567890, השדה audience ב-JWT הוא 1234567890.

הדוגמאות הבאות מראות איך לאמת שאסימון למוכ"ז הונפק על ידי Google Chat וטירגוט לפרויקט שלך באמצעות ספריית הלקוח של OAuth של Google.

Java

java/basic-app/src/main/java/com/google/chat/app/basic/App.java
String CHAT_ISSUER = "chat@system.gserviceaccount.com";
JsonFactory factory = JacksonFactory.getDefaultInstance();

GooglePublicKeysManager keyManagerBuilder =
    new GooglePublicKeysManager.Builder(new ApacheHttpTransport(), factory)
        .setPublicCertsEncodedUrl(
            "https://www.googleapis.com/service_accounts/v1/metadata/x509/" + CHAT_ISSUER)
        .build();

GoogleIdTokenVerifier verifier =
    new GoogleIdTokenVerifier.Builder(keyManagerBuilder).setIssuer(CHAT_ISSUER).build();

GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
return idToken != null
    && verifier.verify(idToken)
    && idToken.verifyAudience(Collections.singletonList(AUDIENCE))
    && idToken.verifyIssuer(CHAT_ISSUER);

Python

python/basic-app/main.py
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

try:
    # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
    request = requests.Request()
    certs_url = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/' + CHAT_ISSUER
    token = id_token.verify_token(bearer, request, AUDIENCE, certs_url)
    return token['iss'] == CHAT_ISSUER

except:
    return False

Node.js

node/basic-app/index.js
// Bearer Tokens received by apps will always specify this issuer.
const chatIssuer = 'chat@system.gserviceaccount.com';

// Verify valid token, signed by CHAT_ISSUER, intended for a third party.
try {
  const response = await fetch('https://www.googleapis.com/service_accounts/v1/metadata/x509/' + chatIssuer);
  const certs = await response.json();
  await client.verifySignedJwtWithCertsAsync(
    bearer, certs, audience, [chatIssuer]);
  return true;
} catch (unused) {
  return false;
}