التحقّق من الطلبات من Google Chat

بالنسبة إلى تطبيقات Google Chat المستندة إلى نقاط نهاية HTTP، يوضّح هذا القسم كيفية التحقّق من أنّ الطلبات الموجّهة إلى نقطة النهاية تأتي من Chat.

لإرسال أحداث التفاعل إلى نقطة النهاية الخاصة بتطبيق Chat، ترسل Google طلبات إلى خدمتك. للتأكّد من أنّ الطلب وارد من Google، يتضمّن Chat رمزًا مميزًا لحامل الإذن في عنوان Authorization لكل طلب HTTPS يتم إرساله إلى نقطة النهاية. على سبيل المثال:

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

السلسلة AbCdEf123456 في المثال السابق هي رمز مميز للترخيص باستخدام حامل الأذونات. هذا رمز مميز مشفّر من إنتاج Google. يعتمد نوع رمز الدخول المميز وحقل audience على نوع جمهور المصادقة الذي اخترته عند إعداد تطبيق Chat.

إذا كنت قد نفّذت تطبيق Chat باستخدام دوال Cloud Run، ستتولّى خدمة Cloud IAM عملية التحقّق من الرمز المميّز تلقائيًا. يجب إضافة حساب خدمة Google Chat كمستخدم معتمد. إذا كان تطبيقك ينفّذ خادم HTTP خاصًا به، يمكنك التحقّق من صحة رمز الحامل باستخدام مكتبة برامج مفتوحة المصدر لعميل Google API:

إذا لم يتم التحقّق من صحة الرمز المميّز لتطبيق Chat، يجب أن ترد خدمتك على الطلب باستخدام رمز استجابة HTTPS 401 (Unauthorized).

مصادقة الطلبات باستخدام دوال Cloud Run

إذا تم تنفيذ منطق الدالة باستخدام دوال Cloud Run، عليك اختيار عنوان URL لنقطة نهاية HTTP في حقل الجمهور المستهدف للمصادقة ضمن إعدادات الربط في تطبيق Chat، والتأكّد من أنّ عنوان URL لنقطة نهاية HTTP في الإعدادات يتطابق مع عنوان URL لنقطة نهاية دالة Cloud Run.

بعد ذلك، عليك منح حساب خدمة Google Chat chat@system.gserviceaccount.com إذن الوصول كمستدعي باستخدام الخطوات التالية:

وحدة التحكّم

بعد نشر الدالة أو الخدمة على Google Cloud، اتّبِع الخطوات التالية:

  1. في Google Cloud Console، انتقِل إلى صفحة Cloud Run:

    الانتقال إلى Cloud Run

  2. في قائمة خدمات Cloud Run، انقر على مربّع الاختيار بجانب الدالة التي تتلقّى البيانات. (لا تنقر على الدالة نفسها).

  3. انقر على الأذونات في أعلى الشاشة. يتم فتح لوحة الأذونات.

  4. انقر على إضافة مدير.

  5. في الحقل الجهات الرئيسية الجديدة، أدخِل chat@system.gserviceaccount.com.

  6. من قائمة اختيار دور، اختَر الدور Cloud Run.

    Cloud Run Invoker

  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.

المصادقة على طلبات HTTP باستخدام رمز مميّز للمعرّف

إذا تم ضبط حقل "الجمهور المستهدف للمصادقة" في إعدادات الربط لتطبيق Chat على عنوان URL لنقطة نهاية HTTP، سيكون رمز المصادقة المميز في الطلب رمز تعريف اتصال OpenID ‏(OIDC) موقّعًا من Google. تم ضبط الحقل email على chat@system.gserviceaccount.com. يتم ضبط حقل الجهة المستهدفة للمصادقة على عنوان URL الذي أعددت Google Chat لإرسال الطلبات إلى تطبيق Chat. على سبيل المثال، إذا كانت نقطة النهاية التي تم ضبطها لتطبيق Chat هي https://example.com/app/، سيكون حقل الجهة المستهدفة للمصادقة في رمز التعريف المميز هو https://example.com/app/.

هذه هي طريقة المصادقة المقترَحة إذا لم تكن نقطة نهاية HTTP مستضافة على خدمة تتيح المصادقة المستندة إلى إدارة الهوية وإمكانية الوصول (IAM) (مثل Cloud Run). باستخدام هذه الطريقة، تحتاج خدمة HTTP إلى معلومات حول عنوان URL لنقطة النهاية التي يتم تشغيلها فيها، ولكنّها لا تحتاج إلى معلومات حول رقم مشروع على السحابة الإلكترونية.

توضّح النماذج التالية كيفية التأكّد من أنّ الرمز المميز لحامل التفويض صادر عن Google Chat وموجّه إلى تطبيقك باستخدام مكتبة عميل Google OAuth.

جافا

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.

لا يُنصح باستخدام طريقة المصادقة هذه إلا إذا كنت تفضّل استخدام رقم مشروع على السحابة الإلكترونية للتحقّق من الطلبات بدلاً من عنوان URL لنقطة نهاية HTTP. على سبيل المثال، إذا أردت تغيير عنوان URL لنقطة النهاية بمرور الوقت مع الاحتفاظ برقم مشروع على السحابة الإلكترونية نفسه، أو إذا أردت استخدام نقطة النهاية نفسها لعدة أرقام مشاريع على السحابة الإلكترونية وأردت مقارنة الحقل audience بقائمة من أرقام المشاريع على السحابة الإلكترونية.

توضّح النماذج التالية كيفية التأكّد من أنّ رمز حامل مميز قد تم إصداره من خلال Google Chat وتم توجيهه إلى مشروعك باستخدام مكتبة عميل Google OAuth.

جافا

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;
}