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

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

Google จะส่งคำขอไปยังบริการของคุณเพื่อส่งเหตุการณ์การโต้ตอบไปยังปลายทางของแอป Chat Chat จะใส่โทเค็นสำหรับผู้ถือในส่วนหัว Authorization ของคำขอ HTTPS ทุกรายการที่ส่งไปยังปลายทางของคุณเพื่อยืนยันว่าคำขอมาจาก Google เช่น

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

สตริง AbCdEf123456 ในตัวอย่างก่อนหน้าคือโทเค็นการให้สิทธิ์แบบ Bearer นี่คือโทเค็นการเข้ารหัสที่ Google สร้างขึ้น ประเภทโทเค็นผู้ถือ และค่าของฟิลด์ audience จะขึ้นอยู่กับประเภทการตรวจสอบสิทธิ์ กลุ่มเป้าหมายที่คุณเลือกเมื่อกำหนดค่าแอป Chat

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

ตัวอย่างต่อไปนี้แสดงวิธีตรวจสอบว่าโทเค็น Bearer ออกโดย Google Chat และกำหนดเป้าหมายไปยังแอปของคุณโดยใช้ไลบรารีของไคลเอ็นต์ 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;
}

ตรวจสอบสิทธิ์คำขอด้วย JWT ของหมายเลขโปรเจ็กต์

หากตั้งค่าฟิลด์กลุ่มเป้าหมายการตรวจสอบสิทธิ์ของการตั้งค่าการเชื่อมต่อแอป Chat เป็น Project Number โทเค็นการให้สิทธิ์แบบ Bearer ในคำขอจะเป็นโทเค็นเว็บ 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

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