Xác minh yêu cầu từ Google Chat

Đối với các ứng dụng Google Chat được xây dựng trên các điểm cuối HTTP, phần này giải thích cách xác minh rằng các yêu cầu đến điểm cuối của bạn là từ Chat.

Để gửi các sự kiện tương tác đến điểm cuối của ứng dụng Chat, Google sẽ gửi yêu cầu đến dịch vụ của bạn. Để xác minh rằng yêu cầu đến từ Google, Chat sẽ thêm một mã thông báo của người mang vào tiêu đề Authorization của mọi yêu cầu HTTPS gửi đến điểm cuối của bạn. Ví dụ:

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

Chuỗi AbCdEf123456 trong ví dụ trước là mã thông báo uỷ quyền của người mang. Đây là mã thông báo mã hoá do Google tạo. Loại mã thông báo của người mang và giá trị của trường audience phụ thuộc vào loại đối tượng xác thực mà bạn đã chọn khi định cấu hình ứng dụng Chat.

Nếu bạn đã triển khai ứng dụng Chat bằng các hàm Cloud Run, thì Cloud IAM sẽ tự động xử lý việc xác minh mã thông báo. Bạn phải thêm tài khoản dịch vụ Google Chat làm người gọi được uỷ quyền. Nếu ứng dụng của bạn triển khai máy chủ HTTP riêng, bạn có thể xác minh mã truy cập của mình bằng thư viện ứng dụng Google API nguồn mở:

Nếu mã thông báo không xác minh được cho ứng dụng Chat, dịch vụ của bạn phải phản hồi yêu cầu bằng mã phản hồi HTTPS 401 (Unauthorized).

Xác thực các yêu cầu bằng cách sử dụng các hàm Cloud Run

Nếu triển khai logic hàm bằng các hàm Cloud Run, bạn phải chọn URL điểm cuối HTTP trong trường Đối tượng xác thực của chế độ cài đặt kết nối Ứng dụng Chat và đảm bảo rằng URL điểm cuối HTTP trong cấu hình tương ứng với URL của điểm cuối hàm Cloud Run.

Sau đó, bạn cần uỷ quyền cho tài khoản dịch vụ Google Chat chat@system.gserviceaccount.com làm trình gọi bằng cách làm theo các bước sau:

Giao diện dòng lệnh

Sau khi triển khai hàm hoặc dịch vụ của bạn lên Google Cloud:

  1. Trong bảng điều khiển Google Cloud, hãy chuyển đến trang Cloud Run:

    Chuyển đến Cloud Run

  2. Trong danh sách dịch vụ Cloud Run, hãy nhấp vào hộp đánh dấu bên cạnh hàm nhận. (Đừng nhấp vào chính hàm đó.)

  3. Nhấp vào Quyền ở đầu màn hình. Bảng Quyền sẽ mở ra.

  4. Nhấp vào Thêm đối tượng chính.

  5. Trong trường New principals (Chủ thể mới), hãy nhập chat@system.gserviceaccount.com.

  6. Trong trình đơn Chọn vai trò, hãy chọn vai trò Cloud Run

    Cloud Run Invoker.

  7. Nhấp vào Lưu.

gcloud

Sử dụng lệnh gcloud functions add-invoker-policy-binding:

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

Thay thế RECEIVING_FUNCTION bằng tên hàm của ứng dụng trò chuyện.

Xác thực các yêu cầu HTTP bằng mã nhận dạng

Nếu trường Đối tượng xác thực của chế độ cài đặt kết nối của ứng dụng Chat được đặt thành URL điểm cuối HTTP, mã thông báo uỷ quyền của người mang trong yêu cầu là mã thông báo nhận dạng OpenID Connect (OIDC) do Google ký. Trường email được đặt thành chat@system.gserviceaccount.com. Trường Đối tượng xác thực được đặt thành URL mà bạn đã định cấu hình Google Chat để gửi yêu cầu đến ứng dụng Chat của bạn. Ví dụ: nếu điểm cuối được định cấu hình của ứng dụng Chat là https://example.com/app/, thì trường Đối tượng xác thực trong mã thông báo nhận dạng là https://example.com/app/.

Đây là phương thức xác thực được đề xuất nếu điểm cuối HTTP của bạn không được lưu trữ trên một dịch vụ hỗ trợ xác thực dựa trên IAM (chẳng hạn như Cloud Run). Khi sử dụng phương thức này, dịch vụ HTTP của bạn cần thông tin về URL của điểm cuối nơi dịch vụ đang chạy, nhưng không cần thông tin về số dự án trên đám mây.

Các mẫu sau đây cho biết cách xác minh rằng mã thông báo của người mang được Google Chat phát hành và nhắm đến ứng dụng của bạn bằng cách sử dụng thư viện ứng dụng Google OAuth.

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

Xác thực các yêu cầu bằng JWT số dự án

Nếu trường Đối tượng xác thực của chế độ cài đặt kết nối Ứng dụng Chat được đặt thành Project Number, thì mã thông báo uỷ quyền của người mang trong yêu cầu là Mã thông báo web JSON (JWT) tự ký, do chat@system.gserviceaccount.com phát hành và ký. Trường audience được đặt thành số dự án trên Google Cloud mà bạn đã dùng để tạo ứng dụng Chat. Ví dụ: nếu số dự án trên Cloud của ứng dụng Chat là 1234567890, thì trường audience trong JWT sẽ là 1234567890.

Bạn chỉ nên dùng phương thức xác thực này nếu muốn sử dụng số dự án trên Cloud để xác minh các yêu cầu thay vì URL điểm cuối HTTP. Ví dụ: nếu bạn muốn thay đổi URL điểm cuối theo thời gian trong khi vẫn giữ nguyên số dự án trên đám mây hoặc nếu bạn muốn sử dụng cùng một điểm cuối cho nhiều số dự án trên đám mây và muốn so sánh trường audience với danh sách số dự án trên đám mây.

Các mẫu sau đây cho biết cách xác minh rằng mã thông báo của người mang đã được Google Chat phát hành và nhắm đến dự án của bạn bằng cách sử dụng thư viện ứng dụng Google OAuth.

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