ยืนยันคำขอจาก Google Chat

สําหรับแอป Google Chat ที่สร้างขึ้นบนปลายทาง HTTP ส่วนนี้จะอธิบายวิธียืนยันว่าคําขอไปยังปลายทางมาจาก Chat

Google จะส่งคำขอไปยังบริการของคุณเพื่อส่งเหตุการณ์การโต้ตอบไปยังปลายทางของแอป Chat เพื่อยืนยันว่าคำขอมาจาก 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 Functions หรือ Cloud Run ไว้แล้ว Cloud IAM จะจัดการการยืนยันโทเค็นโดยอัตโนมัติ คุณเพียงแค่ต้องเพิ่มบัญชีบริการ Google Chat เป็นผู้เรียกใช้ที่ได้รับอนุญาต หากแอปใช้เซิร์ฟเวอร์ HTTP ของตัวเอง คุณสามารถยืนยันโทเค็นของผู้ถือครองได้โดยใช้ไลบรารีของไคลเอ็นต์ Google API แบบโอเพนซอร์ส ดังนี้

หากโทเค็นไม่ยืนยันสําหรับแอป Chat บริการของคุณควรตอบกลับคําขอด้วยรหัสการตอบกลับ HTTPS 401 (Unauthorized)

ตรวจสอบสิทธิ์คําขอโดยใช้ Cloud Functions หรือ Cloud Run

หากใช้ตรรกะฟังก์ชันโดยใช้ Cloud Functions หรือ Cloud Run คุณต้องเลือก URL ปลายทาง HTTP ในช่องกลุ่มเป้าหมายการตรวจสอบสิทธิ์ของแอป Chat การตั้งค่าการเชื่อมต่อ และตรวจสอบว่า URL ปลายทาง HTTP ในการกำหนดค่าสอดคล้องกับ URL ของปลายทาง Cloud Functions หรือ Cloud Run

จากนั้นคุณต้องให้สิทธิ์บัญชีบริการ Google Chat chat@system.gserviceaccount.com ในฐานะผู้เรียกใช้

ขั้นตอนต่อไปนี้แสดงวิธีใช้ Cloud Functions (รุ่นที่ 1)

คอนโซล

หลังจากทำให้ฟังก์ชันใช้งานได้ใน Google Cloud แล้ว ให้ทำดังนี้

  1. ในคอนโซล Google Cloud ให้ไปที่หน้า Cloud Functions แล้วทำดังนี้

    ไปที่ Cloud Functions

  2. ในรายการ Cloud Functions ให้คลิกช่องทําเครื่องหมายข้างฟังก์ชันที่รับ (อย่าคลิกที่ฟังก์ชันนั้น)

  3. คลิกสิทธิ์ที่ด้านบนของหน้าจอ แผงสิทธิ์จะเปิดขึ้น

  4. คลิกเพิ่มผู้ใช้หลัก

  5. ในช่องผู้ใช้หลักใหม่ ให้ป้อน chat@system.gserviceaccount.com

  6. เลือกบทบาท Cloud Functions > Cloud Functions Invoker จากเมนูแบบเลื่อนลงเลือกบทบาท

  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 ด้วยชื่อฟังก์ชันของแอปแชท

ขั้นตอนต่อไปนี้แสดงวิธีใช้บริการ Cloud Functions (รุ่นที่ 2) หรือ Cloud Run

คอนโซล

หลังจากทำให้ฟังก์ชันหรือบริการใช้งานได้ใน 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 เป็นการตั้งค่าการเชื่อมต่อเป็น URL ปลายทาง HTTP โทเค็นการให้สิทธิ์ของผู้ถือครองในคำขอจะเป็นโทเค็นระบุตัวตน OpenID Connect (OIDC) ที่ Google ลงนาม ตั้งค่าช่อง email เป็น chat@system.gserviceaccount.com ช่องกลุ่มเป้าหมายการตรวจสอบสิทธิ์ได้รับการตั้งค่าเป็น URL ที่คุณกำหนดค่าไว้ Google Chat ให้ส่งคำขอไปยังแอป Chat ของคุณ เช่น หากปลายทางที่กำหนดค่าของแอป Chat คือ https://example.com/app/ ช่อง กลุ่มเป้าหมายการตรวจสอบสิทธิ์ในโทเค็นรหัสจะเป็น 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 เช่น หากหมายเลขโปรเจ็กต์ที่อยู่ในระบบคลาวด์ของแอป 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;
}