درستی‌سنجی درخواست‌های Google Chat

برای برنامه‌های Google Chat که در نقطه پایانی HTTP ساخته شده‌اند، این بخش توضیح می‌دهد که چگونه درستی‌سنجی کنید که درخواست‌های نقطه پایانی شما از Chat می‌آیند.

برای ارسال رویدادهای تعامل به نقطه پایانی برنامه Chat شما، Google درخواست‌های HTTPS به سرویس شما ارسال می‌کند. برای تأیید اینکه درخواست از Google می‌آید، Chat یک شناسه وب‌نشانی امضاشده توسط Google را به‌عنوان رمز حامل در سرصفحه Authorization هر درخواست HTTPS (و در فیلد authorizationEventObject.systemIdToken بدنه درخواست) اضافه می‌کند. برای مثال:

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

رشته AbCdEf123456 در مثال قبلی نشانه مجوز حامل است. این کد رمزی با حساب سرویس منحصربه‌فرد برنامه Chat شما که برای هر پروژه تعریف شده است (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) امضا می‌شود، و فیلد audience روی نشانی وب نقطه پایانی HTTP که برای برنامه Chat شما در زمان پیکربندی برنامه Chat پیکربندی شده است تنظیم می‌شود.

می‌توانید نشانی ایمیل حساب سرویس برنامه Chat را از بخش تنظیمات اتصال در برگه پیکربندی Chat API در کنسول Google Cloud کپی کنید:

  1. در کنسول Google Cloud، به منو > میاناهای برنامه‌سازی کاربردی و سرویس‌ها > میاناهای برنامه‌سازی کاربردی و سرویس‌های فعال > میانای برنامه‌سازی کاربردی Google Chat > پیکربندی بروید:

    رفتن به «پیکربندی Google Chat API»

  2. در بخش ویژگی‌های تعاملی > تنظیمات اتصال، ایمیل حساب سرویس (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) را کپی کنید.

اگر برنامه Chat خود را بااستفاده از توابع Cloud Run یا Cloud Run پیاده‌سازی کرده‌اید، وقتی نقش Cloud Run Invoker (roles/run.invoker) را به حساب خدمات برنامه Chat اعطا می‌کنید، Cloud IAM به‌طور خودکار تأیید رمز را انجام می‌دهد. اگر برنامه شما سرور HTTP خود را پیاده‌سازی می‌کند، می‌توانید بااستفاده از کتابخانه مشتری Google API متن‌باز، نشانه حامی را به‌تأیید برسانید:

اگر کد درستی‌سنجی برای برنامه Chat کار نکرد، سرویس شما باید با کد پاسخ HTTPS به درخواست پاسخ دهد 401 (Unauthorized).

اصالت‌سنجی درخواست‌ها بااستفاده از توابع Cloud Run

اگر منطق تابع شما بااستفاده از توابع Cloud Run یا Cloud Run پیاده‌سازی شده است، مطمئن شوید که نشانی‌های وب نقطه پایانی HTTP پیکربندی‌شده در بخش محرک‌ها در تنظیمات اتصال برنامه Chat با نشانی وب نقطه پایانی تابع Cloud Run شما مطابقت داشته باشد.

سپس، حساب سرویس برنامه Chat خود را (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com، کپی‌شده از بخش تنظیمات اتصال در Chat API برگه پیکربندی) به‌عنوان فراخواننده بااستفاده از مراحل زیر مجاز کنید:

کنسول

پس‌از استقرار تابع یا سرویس در Google Cloud:

  1. در کنسول Google Cloud، به صفحه Cloud Run بروید:

    رفتن به Cloud Run

  2. در فهرست خدمات Cloud Run، روی چارگوش انتخاب کنار تابع دریافت‌کننده کلیک کنید. (روی خود تابع کلیک نکنید.)

  3. در بالای صفحه، روی اجازه‌ها کلیک کنید. پانل اجازه‌ها باز می‌شود.

  4. روی افزودن مدیر کلیک کنید.

  5. در فیلد اصول جدید، نشانی ایمیل حساب سرویس برنامه Chat خودتان (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) را وارد کنید.

  6. از منو انتخاب نقش، نقش Cloud Run را انتخاب کنید

    فراخوان Cloud Run.

  7. روی ذخیره کلیک کنید.

gcloud

از فرمان gcloud functions add-invoker-policy-binding استفاده کنید:

gcloud functions add-invoker-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:service-PROJECT_NUMBER@gcp-sa-gsuiteaddons.iam.gserviceaccount.com'

جایگزین کردن موارد زیر:

  • ‫RECEIVING_FUNCTION: نام تابع برنامه Chat شما.
  • ‫PROJECT_NUMBER: شماره پروژه از نشانی ایمیل حساب سرویس برنامه Chat.

درستی‌سنجی درخواست‌های HTTP با «کد شناسایی»

برای نقاط پایان HTTP، ژتون مجوز حامل در درخواست یک ژتون شناسه با امضای Google از نوع OpenID Connect (OIDC) است. فیلد email روی نشانی ایمیل حساب سرویس برنامه Chat شما (service-<var>PROJECT_NUMBER</var>@gcp-sa-gsuiteaddons.iam.gserviceaccount.com) تنظیم شده است، و فیلد audience روی نشانی وب نقطه پایانی HTTP پیکربندی‌شده برای دریافت درخواست تنظیم شده است. برای مثال، اگر نقطه پایانی پیکربندی‌شده برنامه Chat شما https://example.com/app/ باشد، فیلد audience در شناسه رمز https://example.com/app/ است.

اگر نقطه پایان HTTP شما در سرویسی که از اصالت‌سنجی مبتنی بر IAM پشتیبانی می‌کند (مثل Cloud Run) میزبانی نمی‌شود، این روش اصالت‌سنجی توصیه می‌شود.

نمونه‌های زیر نشان می‌دهد که چگونه بااستفاده از کتابخانه مشتری Google OAuth، تأیید کنید که Google توکن حامل را برای برنامه Chat شما صادر کرده است و نقطه پایانی برنامه شما را هدف‌یابی کرده است:

جاوا

java/chat/secured-app/src/main/java/com/google/chat/app/secured/App.java
/**
 * Determine whether a Google Workspace add-on request is legitimate.
 * 
 * @param event Event sent from Google Workspace add-on
 * @param authorization Authorization header from the request
 * @return {boolean} Whether the request is legitimate
 */
private boolean verifyAddOnRequest(JsonNode event, String authorization) throws Exception {
  JsonFactory factory = JacksonFactory.getDefaultInstance();

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

  String bearer = authorization.substring("Bearer ".length(), authorization.length());
  GoogleIdToken idToken = GoogleIdToken.parse(factory, bearer);
  return idToken != null
    && verifier.verify(idToken)
    && idToken.getPayload().getEmailVerified()
    && idToken.getPayload().getEmail().equals(SERVICE_ACCOUNT_EMAIL);
}

Python

python/chat/secured-app/main.py
def verifyAddOnRequest() -> bool:
  """Determine whether a Google Workspace add-on request is legitimate.

  Args:
    request: Request sent from Google Workspace add-on

  Returns:
    Whether the request is legitimate
  """
  try:
    bearer = request.headers.get('Authorization')[len("Bearer "):]
    token = id_token.verify_oauth2_token(bearer, requests.Request(), HTTP_ENDPOINT)
    return token['email'] == SERVICE_ACCOUNT_EMAIL

  except:
    return False

Node.js

node/chat/secured-app/index.js
/**
 * Determine whether a Google Workspace add-on request is legitimate.
 * 
 * @param {Object} req Request sent from Google Workspace add-on
 * @return {boolean} Whether the request is legitimate
 */
async function verifyAddOnRequest(req) {
  try {
    const authorization = req.headers.authorization;
    const idToken = authorization.substring('Bearer '.length, authorization.length);
    const ticket = await new OAuth2Client().verifyIdToken({idToken, audience: HTTP_ENDPOINT});
    return ticket.getPayload().email_verified
        && ticket.getPayload().email === SERVICE_ACCOUNT_EMAIL;
  } catch (unused) {
    return false;
  }
}

برنامه‌های گپ که برافزا نیستند: درخواست‌های Google Chat را به‌تأیید برسانید

مستندات زیر برای برنامه‌های Chat که برافزاهای Google Workspace نیستند اعمال می‌شود. برای انتقال برنامه Chat که برافزا نیست، تبدیل برنامه Google Chat به برافزای Google Workspace را ببینید.

برای برنامه‌های Chat که برافزاهایی نیستند که با نشانی وب نقطه پایانی HTTP در بخش تنظیمات اتصال پیکربندی شده باشند، نوع کد حامل و مقدار فیلد audience به نوع مخاطب اصالت‌سنجی که هنگام پیکربندی برنامه Chat انتخاب کرده‌اید بستگی دارد، و درخواست‌ها با حساب سرویس مشترک chat@system.gserviceaccount.com امضا می‌شوند.

اصالت‌سنجی درخواست‌ها بااستفاده از توابع Cloud Run (برنامه‌های Chat که برافزا نیستند)

اگر منطق تابع شما بااستفاده از توابع Cloud Run پیاده‌سازی شده است، باید نشانی وب نقطه پایانی HTTP را در فیلد مخاطب اصالت‌سنجی در تنظیم اتصال برنامه Chat انتخاب کنید و مطمئن شوید که نشانی وب نقطه پایانی HTTP در پیکربندی با نشانی وب نقطه پایانی تابع Cloud Run مطابقت داشته باشد.

سپس باید حساب سرویس Google Chat chat@system.gserviceaccount.com را به‌عنوان فراخواننده بااستفاده از مراحل زیر مجاز کنید:

کنسول

پس‌از استقرار تابع یا سرویس در Google Cloud:

  1. در کنسول Google Cloud، به صفحه Cloud Run بروید:

    رفتن به Cloud Run

  2. در فهرست خدمات Cloud Run، روی چارگوش انتخاب کنار تابع دریافت‌کننده کلیک کنید. (روی خود تابع کلیک نکنید.)

  3. در بالای صفحه، روی اجازه‌ها کلیک کنید. پانل اجازه‌ها باز می‌شود.

  4. روی افزودن مدیر کلیک کنید.

  5. در فیلد اصول جدید، chat@system.gserviceaccount.com را وارد کنید.

  6. از منو انتخاب نقش، نقش Cloud Run را انتخاب کنید

    فراخوان Cloud Run.

  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 که برافزا نیستند)

اگر فیلد مخاطب اصالت‌سنجی برنامه Chat که برافزا نیست تنظیم اتصال روی نشانی وب نقطه پایان HTTP تنظیم شده باشد، ژتون مجوز حامل در درخواست یک ژتون شناسه OpenID Connect (OIDC) است که با امضای Google ارائه شده است. فیلد email روی chat@system.gserviceaccount.com تنظیم شده است. فیلد مخاطب اصالت‌سنجی روی نشانی وبی تنظیم شده است که Google Chat را پیکربندی کرده‌اید تا درخواست‌ها را به برنامه Chat شما که برافزا نیست ارسال کند. برای مثال، اگر نقطه پایانی پیکربندی‌شده برنامه Chat شما https://example.com/app/ باشد، فیلد مخاطب اصالت‌سنجی در کد شناسایی https://example.com/app/ است.

نمونه‌های زیر نشان می‌دهد چگونه تأیید کنید که حامل نشان توسط Google Chat صادر شده است و برنامه 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 که برافزا نیستند)

اگر فیلد مخاطب اصالت‌سنجی برنامه Chat که برافزا نیست تنظیم اتصال روی Project Number تنظیم شده باشد، توکن مجوز حامل در درخواست یک توکن وب JSON (JWT) خودامضاشده است که chat@system.gserviceaccount.com صادر و امضا کرده است. فیلد audience روی شماره پروژه Google Cloud که برای ساختن برنامه Chat خود استفاده کرده‌اید تنظیم شده است. این برنامه Chat برافزا نیست. برای مثال، اگر شماره پروژه Cloud برنامه Chat شما 1234567890 است، فیلد audience در JWT برابر با 1234567890 است.

نمونه‌های زیر نشان می‌دهد که چگونه بااستفاده از کتابخانه کارخواه Google OAuth تأیید کنید که Google Chat حامل‌برگ را صادر کرده است و پروژه شما را هدف‌یابی کرده است.

جاوا

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