การใช้ OAuth 2.0 สำหรับแอปพลิเคชันเซิร์ฟเวอร์ถึงเซิร์ฟเวอร์

ระบบ Google OAuth 2.0 รองรับการโต้ตอบระหว่างเซิร์ฟเวอร์กับเซิร์ฟเวอร์ เช่น ระหว่างเว็บแอปพลิเคชันและบริการของ Google สำหรับสถานการณ์สมมตินี้คุณจำเป็นต้องมีบัญชีบริการซึ่งเป็นบัญชีที่เป็นของแอพลิเคชันของคุณแทนการไปยังผู้ใช้แต่ละคน แอปพลิเคชันของคุณเรียกใช้ Google API ในนามของบัญชีบริการ ดังนั้นผู้ใช้จะไม่เกี่ยวข้องโดยตรง สถานการณ์นี้บางครั้งเรียกว่า "OAuth แบบสองทาง" หรือ "2LO" (คำว่า "OAuth แบบสามทาง" ที่เกี่ยวข้องหมายถึงสถานการณ์ที่แอปพลิเคชันของคุณเรียกใช้ Google API ในนามของผู้ใช้ปลายทาง และจำเป็นต้องได้รับความยินยอมจากผู้ใช้ในบางครั้ง)

โดยปกติ แอปพลิเคชันจะใช้บัญชีบริการเมื่อแอปพลิเคชันใช้ Google API เพื่อทำงานกับข้อมูลของตัวเอง แทนที่จะเป็นข้อมูลของผู้ใช้ ตัวอย่างเช่น แอปพลิเคชันที่ใช้ Google Cloud Datastore สำหรับการคงอยู่ของข้อมูลจะใช้บัญชีบริการเพื่อตรวจสอบสิทธิ์การเรียกไปยัง Google Cloud Datastore API

ผู้ดูแลระบบโดเมน Google Workspace ยังสามารถ ให้บริการบัญชีผู้มีอำนาจทั้งโดเมน ข้อมูลของผู้ใช้เข้าถึงในนามของผู้ใช้ในโดเมน

เอกสารนี้อธิบายวิธีที่แอปพลิเคชันสามารถดำเนินการตามขั้นตอน OAuth 2.0 แบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์โดยใช้ไลบรารีไคลเอ็นต์ Google APIs (แนะนำ) หรือ HTTP

ภาพรวม

ที่ให้การสนับสนุนการมีปฏิสัมพันธ์เซิร์ฟเวอร์ไปยังเซิร์ฟเวอร์แรกสร้างบัญชีผู้ใช้บริการสำหรับโครงการของคุณใน API Consoleหากคุณต้องการเข้าถึงข้อมูลผู้ใช้สำหรับผู้ใช้ในบัญชี Google Workspace ให้มอบสิทธิ์การเข้าถึงทั้งโดเมนให้กับบัญชีบริการ

จากนั้น แอปพลิเคชันของคุณจะเตรียมการเรียก API ที่ได้รับอนุญาตโดยใช้ข้อมูลประจำตัวของบัญชีบริการเพื่อขอโทเค็นการเข้าถึงจากเซิร์ฟเวอร์การตรวจสอบสิทธิ์ OAuth 2.0

สุดท้าย แอปพลิเคชันของคุณสามารถใช้โทเค็นเพื่อการเข้าถึงเพื่อเรียกใช้ Google API

การสร้างบัญชีบริการ

ข้อมูลประจำตัวของบัญชีบริการประกอบด้วยที่อยู่อีเมลที่สร้างขึ้นซึ่งไม่ซ้ำกันและมีคู่คีย์สาธารณะ/ส่วนตัวอย่างน้อยหนึ่งคู่ หากเปิดใช้การมอบสิทธิ์ทั่วทั้งโดเมน รหัสไคลเอ็นต์จะเป็นส่วนหนึ่งของข้อมูลรับรองของบัญชีบริการด้วย

หากแอปพลิเคชันของคุณทำงานบน Google App Engine บัญชีบริการจะได้รับการตั้งค่าโดยอัตโนมัติเมื่อคุณสร้างโครงการ

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

หากใบสมัครของคุณไม่ได้ทำงานบน Google App Engine หรือ Google Compute Engine คุณจะต้องได้รับสิทธิเหล่านี้ใน Google API Consoleในการสร้างข้อมูลประจำตัวของบัญชีบริการ หรือเพื่อดูข้อมูลประจำตัวสาธารณะที่คุณได้สร้างไว้แล้ว ให้ทำดังต่อไปนี้:

First, create a service account:

  1. Open the Service accounts page.
  2. If prompted, select a project, or create a new one.
  3. Click  Create service account.
  4. Under Service account details, type a name, ID, and description for the service account, then click Create and continue.
  5. Optional: Under Grant this service account access to project, select the IAM roles to grant to the service account.
  6. Click Continue.
  7. Optional: Under Grant users access to this service account, add the users or groups that are allowed to use and manage the service account.
  8. Click Done.
  9. Click  Create key, then click Create.

Next, create a service account key:

  1. Click the email address for the service account you created.
  2. Click the Keys tab.
  3. In the Add key drop-down list, select Create new key.
  4. Click Create.

Your new public/private key pair is generated and downloaded to your machine; it serves as the only copy of the private key. You are responsible for storing it securely. If you lose this key pair, you will need to generate a new one.

คุณสามารถกลับไปที่ API Console ได้ตลอดเวลาเพื่อดูที่อยู่อีเมลลายนิ้วมือคีย์สาธารณะและข้อมูลอื่น ๆ หรือการสร้างสาธารณะ / คู่คีย์เพิ่มเติมส่วนตัว สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับข้อมูลประจำตัวของบัญชีผู้ใช้บริการใน API Consoleดู บัญชีบริการ ใน API Consoleแฟ้มความช่วยเหลือ

จดที่อยู่อีเมลของบัญชีบริการและจัดเก็บไฟล์คีย์ส่วนตัวของบัญชีบริการไว้ในตำแหน่งที่แอปพลิเคชันของคุณสามารถเข้าถึงได้ แอปพลิเคชันของคุณต้องการให้เรียกใช้ API ที่ได้รับอนุญาต

การมอบอำนาจทั่วทั้งโดเมนให้กับบัญชีบริการ

หากคุณมีบัญชี Google Workspace ผู้ดูแลระบบขององค์กรจะอนุญาตให้แอปพลิเคชันเข้าถึงข้อมูลผู้ใช้ในนามของผู้ใช้ในโดเมน Google Workspace ตัวอย่างเช่น แอปพลิเคชันที่ใช้ Google Calendar API เพื่อเพิ่มกิจกรรมในปฏิทินของผู้ใช้ทั้งหมดในโดเมน Google Workspace จะใช้บัญชีบริการเพื่อเข้าถึง Google Calendar API ในนามของผู้ใช้ การอนุญาตให้บัญชีบริการเข้าถึงข้อมูลในนามของผู้ใช้ในโดเมนบางครั้งเรียกว่า "การมอบอำนาจทั่วทั้งโดเมน" ให้กับบัญชีบริการ

ในการมอบอำนาจทั่วทั้งโดเมนให้กับบัญชีบริการ ผู้ดูแลระบบขั้นสูงของโดเมน Google Workspace ต้องทำตามขั้นตอนต่อไปนี้

  1. จาก Google พื้นที่ทำงานของโดเมน คอนโซลการดูแลระบบ ให้ไปที่เมนูหลัก > ความปลอดภัย> การควบคุมการ API
  2. ในบานหน้าต่างกว้างคณะผู้แทนโดเมนเลือกจัดการโดเมนคณะผู้แทนไวด์
  3. คลิกที่เพิ่มใหม่
  4. ในฟิลด์รหัสลูกค้าให้ป้อนรหัสลูกค้าบัญชีผู้ใช้บริการของ คุณสามารถค้นหารหัสลูกค้าบัญชีผู้ใช้บริการของคุณใน Service accounts page
  5. ในขอบเขต OAuth ฟิลด์ (คั่นด้วยจุลภาค) ป้อนรายการขอบเขตว่าโปรแกรมที่คุณควรจะได้รับการเข้าถึง ตัวอย่างเช่นถ้าใบสมัครของคุณต้องการการเข้าถึงทั้งโดเมนแบบเต็มไปยัง API ของ Google ไดรฟ์และ API ของ Google ปฏิทินป้อน: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth / ปฏิทิน
  6. คลิกอนุญาต

ตอนนี้ แอปพลิเคชันของคุณมีอำนาจในการเรียก API ในฐานะผู้ใช้ในโดเมนของคุณ (เพื่อ "เลียนแบบ" ผู้ใช้) เมื่อคุณเตรียมที่จะทำการเรียก API ที่ได้รับอนุญาต คุณต้องระบุผู้ใช้ที่จะแอบอ้าง

กำลังเตรียมการเรียก API ที่ได้รับอนุญาต

Java

หลังจากที่คุณได้รับที่อยู่อีเมลของลูกค้าและคีย์ส่วนตัวจาก API Consoleใช้ ห้องสมุดไคลเอ็นต์ Google APIs สำหรับ Java เพื่อสร้าง GoogleCredential วัตถุจากข้อมูลประจำตัวของบัญชีผู้ใช้บริการและขอบเขตการใช้งานของคุณต้องการเข้าถึง ตัวอย่างเช่น:

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.sqladmin.SQLAdminScopes;

// ...

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN));

หากคุณมีการพัฒนา app บนแพลตฟอร์มคลาวด์ของ Google คุณสามารถใช้ ข้อมูลประจำตัวของโปรแกรมเริ่มต้น แทนซึ่งสามารถลดความซับซ้อนของกระบวนการ

มอบอำนาจทั่วทั้งโดเมน

หากคุณได้มอบการเข้าถึงทั้งโดเมนไปยังบัญชีของบริการและคุณต้องการที่จะเลียนแบบบัญชีผู้ใช้ที่ระบุที่อยู่อีเมลของบัญชีผู้ใช้ที่มี createDelegated วิธีการ GoogleCredential วัตถุ ตัวอย่างเช่น:

GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"))
    .createScoped(Collections.singleton(SQLAdminScopes.SQLSERVICE_ADMIN))
    .createDelegated("user@example.com");

ใช้ GoogleCredential วัตถุที่จะเรียก Google APIs ในใบสมัครของคุณ

Python

หลังจากที่คุณได้รับที่อยู่อีเมลของลูกค้าและคีย์ส่วนตัวจาก API Consoleใช้ ห้องสมุดไคลเอ็นต์ Google APIs สำหรับหลาม ทำตามขั้นตอนต่อไปนี้:

  1. สร้าง Credentials ของวัตถุจากข้อมูลประจำตัวของบัญชีผู้ใช้บริการและขอบเขตการใช้งานของคุณต้องการเข้าถึง ตัวอย่างเช่น:
    from google.oauth2 import service_account
    
    SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
    SERVICE_ACCOUNT_FILE = '/path/to/service.json'
    
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)

    หากคุณมีการพัฒนา app บนแพลตฟอร์มคลาวด์ของ Google คุณสามารถใช้ ข้อมูลประจำตัวของโปรแกรมเริ่มต้น แทนซึ่งสามารถลดความซับซ้อนของกระบวนการ

  2. มอบอำนาจทั่วทั้งโดเมน

    หากคุณได้มอบการเข้าถึงทั้งโดเมนไปยังบัญชีของบริการและคุณต้องการที่จะเลียนแบบบัญชีผู้ใช้ที่ใช้ with_subject วิธีการที่มีอยู่ ServiceAccountCredentials วัตถุ ตัวอย่างเช่น:

    delegated_credentials = credentials.with_subject('user@example.org')

ใช้อ็อบเจ็กต์ Credentials เพื่อเรียก Google APIs ในแอปพลิเคชันของคุณ

HTTP/REST

หลังจากที่คุณได้รับรหัสลูกค้าและคีย์ส่วนตัวจาก API Consoleแอพลิเคชันของคุณต้องทำตามขั้นตอนต่อไปนี้:

  1. สร้าง JSON Web Token (JWT ออกเสียงว่า "jot") ซึ่งประกอบด้วยส่วนหัว ชุดการอ้างสิทธิ์ และลายเซ็น
  2. ขอโทเค็นการเข้าถึงจากเซิร์ฟเวอร์การให้สิทธิ์ Google OAuth 2.0
  3. จัดการการตอบสนอง JSON ที่ Authorization Server ส่งคืน

ส่วนต่างๆ ที่ตามมาจะอธิบายวิธีการทำตามขั้นตอนเหล่านี้

ถ้าตอบรวมถึงโทเค็นการเข้าถึงคุณสามารถใช้การเข้าถึงโทเค็นการ เรียก API ของ Google (หากการตอบกลับไม่มีโทเค็นเพื่อการเข้าถึง คำขอ JWT และโทเค็นของคุณอาจมีรูปแบบไม่ถูกต้อง หรือบัญชีบริการอาจไม่ได้รับอนุญาตให้เข้าถึงขอบเขตที่ร้องขอ)

เมื่อโทเค็นการเข้าถึง หมดอายุ แอพลิเคชันของคุณสร้าง JWT อีกสัญญาณมันและขอโทเค็นการเข้าถึงอื่น

แอปพลิเคชันเซิร์ฟเวอร์ของคุณใช้ JWT เพื่อขอโทเค็นจากเซิร์ฟเวอร์การอนุญาตของ Google จากนั้นใช้โทเค็นเพื่อเรียกตำแหน่งข้อมูล Google API ไม่มีผู้ใช้ปลายทางที่เกี่ยวข้อง

ส่วนที่เหลือของส่วนนี้จะอธิบายรายละเอียดเฉพาะของการสร้าง JWT การลงนาม JWT การสร้างคำขอโทเค็นการเข้าถึง และการจัดการการตอบกลับ

การสร้าง JWT

JWT ประกอบด้วยสามส่วน: ส่วนหัว ชุดการอ้างสิทธิ์ และลายเซ็น ส่วนหัวและชุดการอ้างสิทธิ์เป็นออบเจ็กต์ JSON ออบเจ็กต์ JSON เหล่านี้จัดลำดับเป็นไบต์ UTF-8 จากนั้นเข้ารหัสโดยใช้การเข้ารหัส Base64url การเข้ารหัสนี้ให้ความยืดหยุ่นต่อการเปลี่ยนแปลงการเข้ารหัสอันเนื่องมาจากการดำเนินการเข้ารหัสซ้ำๆ ส่วนหัวชุดเรียกร้องและลายเซ็นจะตัดแบ่งกันที่มีระยะเวลา ( . ) ตัวละคร

JWT ประกอบด้วย:

{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}

สตริงฐานสำหรับลายเซ็นมีดังนี้:

{Base64url encoded header}.{Base64url encoded claim set}
การสร้างส่วนหัว JWT

ส่วนหัวประกอบด้วยสองฟิลด์ที่ระบุอัลกอริทึมการเซ็นชื่อและรูปแบบของการยืนยัน ทั้งสองฟิลด์เป็นฟิลด์บังคับ และแต่ละฟิลด์มีค่าเพียงค่าเดียว เมื่อมีการแนะนำอัลกอริธึมและรูปแบบเพิ่มเติม ส่วนหัวนี้จะเปลี่ยนไปตามนั้น

บัญชีบริการใช้อัลกอริทึม RSA SHA-256 และรูปแบบโทเค็น JWT ด้วยเหตุนี้ การแสดง JSON ของส่วนหัวจึงเป็นดังนี้:

{"alg":"RS256","typ":"JWT"}

การแสดง Base64url ของสิ่งนี้มีดังนี้:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
การสร้างชุดการเรียกร้อง JWT

ชุดการอ้างสิทธิ์ JWT ประกอบด้วยข้อมูลเกี่ยวกับ JWT รวมถึงการอนุญาตที่ร้องขอ (ขอบเขต) เป้าหมายของโทเค็น ผู้ออก เวลาที่ออกโทเค็น และอายุการใช้งานของโทเค็น ฟิลด์ส่วนใหญ่เป็นฟิลด์บังคับ เช่นเดียวกับส่วนหัว JWT ชุดการอ้างสิทธิ์ JWT เป็นอ็อบเจ็กต์ JSON และใช้ในการคำนวณลายเซ็น

การเรียกร้องที่จำเป็น

การอ้างสิทธิ์ที่จำเป็นในชุดการเคลม JWT แสดงอยู่ด้านล่าง พวกเขาอาจปรากฏในลำดับใด ๆ ในชุดการอ้างสิทธิ์

ชื่อ คำอธิบาย
iss ที่อยู่อีเมลของบัญชีบริการ
scope รายการการอนุญาตที่คั่นด้วยช่องว่างที่แอปพลิเคชันร้องขอ
aud ตัวบ่งชี้เป้าหมายที่ตั้งใจไว้ของการยืนยัน เมื่อมีการเข้าถึงโทเค็นคำขอค่านี้อยู่เสมอ https://oauth2.googleapis.com/token
exp เวลาหมดอายุของการยืนยัน ซึ่งระบุเป็นวินาทีตั้งแต่ 00:00:00 UTC วันที่ 1 มกราคม 1970 ค่านี้มีสูงสุด 1 ชั่วโมงหลังจากเวลาที่ออก
iat เวลาที่ออกการยืนยัน โดยระบุเป็นวินาทีตั้งแต่ 00:00:00 UTC วันที่ 1 มกราคม 1970

การแสดง JSON ของฟิลด์ที่จำเป็นในชุดการอ้างสิทธิ์ JWT แสดงอยู่ด้านล่าง:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/devstorage.read_only",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
การเรียกร้องเพิ่มเติม

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

ที่จะได้รับการเข้าถึงโทเค็นที่ให้เข้าถึงแอปพลิเคมอบหมายให้ทรัพยากรรวมถึงที่อยู่อีเมลของผู้ใช้ที่อยู่ในชุด JWT เรียกร้องเป็นค่าของที่ sub ฟิลด์

ชื่อ คำอธิบาย
sub ที่อยู่อีเมลของผู้ใช้ที่แอปพลิเคชันร้องขอการเข้าถึงที่ได้รับมอบสิทธิ์

ถ้าโปรแกรมประยุกต์ไม่ได้รับอนุญาตให้ปลอมตัวเป็นผู้ใช้, การตอบสนองต่อการเข้าถึงโทเค็นคำขอที่มีการ sub ข้อมูลจะเป็น ข้อผิดพลาด

ตัวอย่างของการตั้งค่าการเรียกร้อง JWT ที่มีการ sub ข้อมูลที่แสดงด้านล่าง:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "sub": "some.user@example.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
การเข้ารหัสชุดการอ้างสิทธิ์ JWT

เช่นเดียวกับส่วนหัว JWT ชุดการอ้างสิทธิ์ JWT ควรถูกทำให้เป็นอนุกรมเป็น UTF-8 และเข้ารหัสแบบปลอดภัย Base64url ด้านล่างนี้เป็นตัวอย่างของการแทนค่า JSON ของชุด JWT Claim:

{
  "iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
  "scope": "https://www.googleapis.com/auth/prediction",
  "aud": "https://oauth2.googleapis.com/token",
  "exp": 1328554385,
  "iat": 1328550785
}
การคำนวณลายเซ็น

JSON เว็บลายเซ็น (JWS) เป็นสเปคที่แนะนำกลศาสตร์ในการสร้างลายเซ็นสำหรับ JWT ที่ อินพุตสำหรับลายเซ็นคืออาร์เรย์ไบต์ของเนื้อหาต่อไปนี้:

{Base64url encoded header}.{Base64url encoded claim set}

ต้องใช้อัลกอริทึมการลงนามในส่วนหัว JWT เมื่อคำนวณลายเซ็น อัลกอริทึมการเซ็นชื่อเดียวที่รองรับโดยเซิร์ฟเวอร์การอนุญาต Google OAuth 2.0 คือ RSA โดยใช้อัลกอริทึมการแฮช SHA-256 นี้จะแสดงเป็น RS256 ใน alg ฟิลด์ในส่วนหัวของ JWT

ลงนามใน UTF-8 เป็นตัวแทนของการป้อนข้อมูลโดยใช้ SHA256withRSA (ยังเป็นที่รู้จักในฐานะ RSASSA-PKCS1-V1_5 เข้าสู่ระบบด้วยฟังก์ชันแฮช SHA-256) กับคีย์ส่วนตัวที่ได้จาก Google API Consoleผลลัพธ์จะเป็นอาร์เรย์ไบต์

ลายเซ็นจะต้องเข้ารหัส Base64url ส่วนหัวชุดเรียกร้องและลายเซ็นจะตัดแบ่งกันที่มีระยะเวลา ( . ) ตัวละคร ผลลัพธ์คือ JWT ควรเป็นดังนี้ (เพิ่มตัวแบ่งบรรทัดเพื่อความชัดเจน):

{Base64url encoded header}.
{Base64url encoded claim set}.
{Base64url encoded signature}

ด้านล่างนี้เป็นตัวอย่างของ JWT ก่อนการเข้ารหัส Base64url:

{"alg":"RS256","typ":"JWT"}.
{
"iss":"761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/prediction",
"aud":"https://oauth2.googleapis.com/token",
"exp":1328554385,
"iat":1328550785
}.
[signature bytes]

ด้านล่างนี้เป็นตัวอย่างของ JWT ที่ลงนามและพร้อมสำหรับการส่ง:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL29hdXRoMi92NC90b2tlbiIsImV4cCI6MTMyODU1NDM4NSwiaWF0IjoxMzI4NTUwNzg1fQ.UFUt59SUM2_AW4cRU8Y0BYVQsNTo4n7AFsNrqOpYiICDu37vVt-tw38UKzjmUKtcRsLLjrR3gFW3dNDMx_pL9DVjgVHDdYirtrCekUHOYoa1CMR66nxep5q5cBQ4y4u2kIgSvChCTc9pmLLNoIem-ruCecAJYgI9Ks7pTnW1gkOKs0x3YpiLpzplVHAkkHztaXiJdtpBcY1OXyo6jTQCa3Lk2Q3va1dPkh_d--GU2M5flgd8xNBPYw4vxyt0mP59XZlHMpztZt0soSgObf7G3GXArreF_6tpbFsS3z2t5zkEiHuWJXpzcYr5zWTRPDEHsejeBSG8EgpLDce2380ROQ

ทำการร้องขอโทเค็นการเข้าถึง

หลังจากสร้าง JWT ที่ลงนามแล้ว แอปพลิเคชันสามารถใช้เพื่อขอโทเค็นการเข้าถึงได้ การเข้าถึงโทเค็นคำขอนี้เป็น HTTPS POST คำขอและร่างกายคือ URL ที่เข้ารหัส URL แสดงอยู่ด้านล่าง:

https://oauth2.googleapis.com/token

พารามิเตอร์ต่อไปนี้จะต้องอยู่ใน HTTPS POST คำขอ:

ชื่อ คำอธิบาย
grant_type ใช้สตริงต่อไปนี้, เข้ารหัส URL ตามความจำเป็น: urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JWT รวมทั้งลายเซ็น

ข้างล่างนี้คือการถ่ายโอนข้อมูลดิบของ HTTPS POST คำขอใช้ในการเข้าถึงโทเค็นคำขอ:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.ixOUGehweEVX_UKXv5BbbwVEdcz6AYS-6uQV6fGorGKrHf3LIJnyREw9evE-gs2bmMaQI5_UbabvI4k-mQE4kBqtmSpTzxYBL1TCd7Kv5nTZoUC1CmwmWCFqT9RE6D7XSgPUh_jF1qskLa2w0rxMSjwruNKbysgRNctZPln7cqQ

ด้านล่างเป็นคำขอเดียวกันโดยใช้ curl :

curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3NjEzMjY3OTgwNjktcjVtbGpsbG4xcmQ0bHJiaGc3NWVmZ2lncDM2bTc4ajVAZGV2ZWxvcGVyLmdzZXJ2aWNlYWNjb3VudC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvcHJlZGljdGlvbiIsImF1ZCI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsImV4cCI6MTMyODU3MzM4MSwiaWF0IjoxMzI4NTY5NzgxfQ.RZVpzWygMLuL-n3GwjW1_yhQhrqDacyvaXkuf8HcJl8EtXYjGjMaW5oiM5cgAaIorrqgYlp4DPF_GuncFqg9uDZrx7pMmCZ_yHfxhSCXru3gbXrZvAIicNQZMFxrEEn4REVuq7DjkTMyCMGCY1dpMa8aWfTQFt3Eh7smLchaZsU
' https://oauth2.googleapis.com/token

การจัดการการตอบสนอง

หากคำขอ JWT และโทเค็นการเข้าถึงมีรูปแบบที่เหมาะสม และบัญชีบริการมีสิทธิ์ดำเนินการ การตอบสนอง JSON จากเซิร์ฟเวอร์การอนุญาตจะรวมโทเค็นการเข้าถึงไว้ด้วย ต่อไปนี้เป็นตัวอย่างการตอบสนอง:

{
  "access_token": "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M",
  "scope": "https://www.googleapis.com/auth/prediction"
  "token_type": "Bearer",
  "expires_in": 3600
}

ราชสกุลเข้าถึงสามารถนำกลับมาใช้ในช่วงระยะเวลาที่หน้าต่างที่ระบุโดย expires_in ค่า

เรียก Google APIs

Java

ใช้ GoogleCredential วัตถุที่จะเรียก Google APIs โดยทำตามขั้นตอนต่อไปนี้:

  1. สร้างวัตถุบริการ API ที่คุณต้องการที่จะเรียกใช้ GoogleCredential วัตถุ ตัวอย่างเช่น:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. ร้องขอทำให้การให้บริการ API โดยใช้ อินเตอร์เฟซที่จัดไว้ให้โดยวัตถุบริการ ตัวอย่างเช่นในกรณีของรายการฐานข้อมูล Cloud SQL ในน่าตื่นเต้นเช่น-123 โครงการ:
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

ใช้ผู้มีอำนาจของ Credentials คัดค้านการเรียก Google APIs โดยทำตามขั้นตอนต่อไปนี้:

  1. สร้างวัตถุบริการสำหรับ API ที่คุณต้องการเรียกใช้ คุณสร้างวัตถุบริการ AA โดยการเรียก build ฟังก์ชั่นที่มีชื่อและรุ่นของ API และได้รับอนุญาต Credentials วัตถุ ตัวอย่างเช่นในการเรียกรุ่น 1beta3 ของ Cloud SQL บริหาร API:
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. ร้องขอทำให้การให้บริการ API โดยใช้ อินเตอร์เฟซที่จัดไว้ให้โดยวัตถุบริการ ตัวอย่างเช่นในกรณีของรายการฐานข้อมูล Cloud SQL ในน่าตื่นเต้นเช่น-123 โครงการ:
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP/REST

หลังจากที่แอปพลิเคชันของคุณได้รับโทเค็นเพื่อการเข้าถึงแล้ว คุณสามารถใช้โทเค็นดังกล่าวเพื่อทำการเรียกไปยัง Google API ในนามของบัญชีบริการหรือบัญชีผู้ใช้ที่ระบุได้ หากได้รับการอนุญาตขอบเขตการเข้าถึงที่กำหนดโดย API การทำเช่นนี้รวมถึงการเข้าถึงโทเค็นในการร้องขอไปยัง API โดยรวมทั้ง access_token พารามิเตอร์การค้นหาหรือ Authorization ส่วนหัว HTTP Bearer คุ้มค่า หากเป็นไปได้ ควรใช้ส่วนหัว HTTP เนื่องจากสตริงการสืบค้นมักจะมองเห็นได้ในบันทึกของเซิร์ฟเวอร์ ในกรณีส่วนใหญ่คุณสามารถใช้ห้องสมุดลูกค้าในการตั้งค่าการโทรของคุณไปยัง Google APIs (ตัวอย่างเช่นเมื่อ การเรียกไฟล์ API ไดรฟ์ )

คุณสามารถลองออกทั้งหมดของ Google APIs และดูขอบเขตของพวกเขาที่ สนามเด็กเล่น OAuth 2.0

ตัวอย่าง HTTP GET

โทรไป drive.files ปลายทาง (ไฟล์ไดรฟ์ API) โดยใช้ Authorization: Bearer HTTP ส่วนหัวอาจมีลักษณะดังต่อไปนี้ โปรดทราบว่าคุณต้องระบุโทเค็นการเข้าถึงของคุณเอง:

GET /drive/v2/files HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer access_token

นี่คือการเรียก API เดียวกันสำหรับผู้ใช้รับรองความถูกต้องโดยใช้ access_token พารามิเตอร์สตริงการสืบค้น:

GET https://www.googleapis.com/drive/v2/files?access_token=access_token

curl ตัวอย่าง

คุณสามารถทดสอบคำสั่งเหล่านี้กับ curl ประยุกต์ใช้บรรทัดคำสั่ง นี่คือตัวอย่างที่ใช้ตัวเลือกส่วนหัว HTTP (แนะนำ):

curl -H "Authorization: Bearer access_token" https://www.googleapis.com/drive/v2/files

หรือตัวเลือกพารามิเตอร์สตริงข้อความค้นหา:

curl https://www.googleapis.com/drive/v2/files?access_token=access_token

เมื่อโทเค็นการเข้าถึงหมดอายุ

โทเค็นที่ออกโดย Google OAuth 2.0 การอนุญาตเซิร์ฟเวอร์หมดอายุหลังจากระยะเวลาที่มีให้โดย expires_in ค่า เมื่อโทเค็นการเข้าถึงหมดอายุ แอปพลิเคชันควรสร้าง JWT อื่น ลงนาม และขอโทเค็นการเข้าถึงอื่น

รหัสข้อผิดพลาด JWT

error ข้อมูล error_description ฟิลด์ ความหมาย วิธีแก้ปัญหา
unauthorized_client Unauthorized client or scope in request. หากคุณกำลังพยายามใช้การมอบสิทธิ์ทั่วทั้งโดเมน บัญชีบริการจะไม่ได้รับสิทธิ์ในคอนโซลผู้ดูแลระบบของโดเมนของผู้ใช้

ตรวจสอบให้แน่ใจว่าบัญชีผู้ใช้บริการเป็นผู้มีอำนาจใน คณะผู้แทนโดเมนกว้าง หน้าของคอนโซลผู้ดูแลระบบสำหรับผู้ใช้ใน sub เรียกร้อง (เขต)

แม้ว่าโดยทั่วไปจะใช้เวลาสองสามนาที แต่อาจใช้เวลาถึง 24 ชั่วโมงในการให้สิทธิ์ในการเผยแพร่ไปยังผู้ใช้ทั้งหมดในบัญชี Google ของคุณ

unauthorized_client Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested. บัญชีบริการได้รับอนุญาตโดยใช้ที่อยู่อีเมลของไคลเอ็นต์แทนรหัสไคลเอ็นต์ (ตัวเลข) ในคอนโซลผู้ดูแลระบบ ใน คณะผู้แทนโดเมนกว้าง หน้าคอนโซลผู้ดูแลระบบเอาลูกค้าและเพิ่มมันมีรหัสตัวเลข
access_denied (ค่าใดก็ได้) หากคุณกำลังใช้การมอบสิทธิ์ทั่วทั้งโดเมน ขอบเขตที่ขออย่างน้อยหนึ่งขอบเขตจะไม่ได้รับสิทธิ์ในคอนโซลผู้ดูแลระบบ

ตรวจสอบให้แน่ใจว่าบัญชีผู้ใช้บริการเป็นผู้มีอำนาจใน คณะผู้แทนโดเมนกว้าง หน้าของคอนโซลผู้ดูแลระบบสำหรับผู้ใช้ใน sub เรียกร้อง (เขต) และว่ามันรวมทั้งหมดของขอบเขตคุณขอใน scope การเรียกร้องของ JWT ของคุณ

แม้ว่าโดยทั่วไปจะใช้เวลาสองสามนาที แต่อาจใช้เวลาถึง 24 ชั่วโมงในการให้สิทธิ์ในการเผยแพร่ไปยังผู้ใช้ทั้งหมดในบัญชี Google ของคุณ

invalid_grant Not a valid email. ไม่มีผู้ใช้รายนี้ ตรวจสอบว่าที่อยู่อีเมลใน sub เรียกร้อง (เขต) เป็นที่ถูกต้อง
invalid_grant

Invalid JWT: Token must be a short-lived token (60 minutes) and in a reasonable timeframe. Check your 'iat' and 'exp' values and use a clock with skew to account for clock differences between systems.

โดยปกติหมายความว่าเวลาของระบบท้องถิ่นไม่ถูกต้อง นอกจากนี้ยังอาจเกิดขึ้นได้หาก exp มูลค่ากว่า 65 นาทีในอนาคตจาก iat คุ้มค่าหรือ exp มูลค่าต่ำกว่า iat ค่า

ตรวจสอบให้แน่ใจว่านาฬิกาบนระบบที่สร้าง JWT นั้นถูกต้อง ถ้าจำเป็นซิงค์เวลาของคุณกับ Google NTP

invalid_grant Invalid JWT Signature.

การยืนยัน JWT ได้รับการลงนามด้วยคีย์ส่วนตัวที่ไม่เชื่อมโยงกับบัญชีบริการที่ระบุโดยอีเมลไคลเอ็นต์หรือคีย์ที่ใช้ถูกลบ ปิดใช้งาน หรือหมดอายุแล้ว

อีกวิธีหนึ่ง การยืนยัน JWT อาจถูกเข้ารหัสอย่างไม่ถูกต้อง - ต้องเป็นการเข้ารหัส Base64 โดยไม่มีการขึ้นบรรทัดใหม่หรือการเติมเครื่องหมายเท่ากับ

ถอดรหัสชุดการอ้างสิทธิ์ JWT และตรวจสอบว่าคีย์ที่ลงนามในการยืนยันเชื่อมโยงกับบัญชีบริการ

ลองใช้ไลบรารี OAuth ที่ Google จัดหาให้เพื่อให้แน่ใจว่า JWT ถูกสร้างขึ้นอย่างถูกต้อง

invalid_scope Invalid OAuth scope or ID token audience provided. ไม่มีการร้องขอขอบเขต (รายการขอบเขตที่ว่างเปล่า) หรือหนึ่งในขอบเขตที่ร้องขอไม่มีอยู่ (เช่น ไม่ถูกต้อง)

ตรวจสอบให้แน่ใจว่า scope การเรียกร้อง (เขต) ของ JWT เป็นประชากรและเปรียบเทียบขอบเขตที่ว่ามันมีกับขอบเขตเอกสารสำหรับ API ที่คุณต้องการใช้งานเพื่อให้แน่ใจว่าไม่มีข้อผิดพลาดหรือความผิดพลาด

หมายเหตุว่ารายการของขอบเขตในส่วน scope ความต้องการเรียกร้องที่จะคั่นด้วยช่องว่างไม่จุลภาค

disabled_client The OAuth client was disabled. คีย์ที่ใช้ในการลงนามในการยืนยัน JWT ถูกปิดใช้งาน

ไปที่ Google API Consoleและภายใต้ IAM และผู้ดูแลระบบ> บัญชีบริการให้เปิดใช้งานบัญชีผู้ใช้บริการซึ่งมี "รหัสคีย์" ใช้ในการลงชื่อยืนยัน

ภาคผนวก: การอนุญาตบัญชีบริการโดยไม่มี OAuth

ด้วย Google API บางตัว คุณสามารถทำการเรียก API ที่ได้รับอนุญาตโดยใช้ JWT ที่ลงนามโดยตรงเป็นโทเค็นสำหรับผู้ถือ แทนที่จะเป็นโทเค็นการเข้าถึง OAuth 2.0 เมื่อเป็นไปได้ คุณสามารถหลีกเลี่ยงการร้องขอเครือข่ายไปยังเซิร์ฟเวอร์การให้สิทธิ์ของ Google ก่อนทำการเรียก API

หาก API ที่คุณต้องการโทรมีความหมายบริการที่ตีพิมพ์ใน พื้นที่เก็บข้อมูล Google APIs GitHub คุณสามารถโทร API ที่ได้รับอนุญาตใช้ JWT แทนโทเค็นการเข้าถึง ในการทำเช่นนั้น:

  1. สร้างบัญชีผู้ใช้บริการ ตามที่อธิบายไว้ข้างต้น อย่าลืมเก็บไฟล์ JSON ที่คุณได้รับเมื่อคุณสร้างบัญชี
  2. การใช้ห้องสมุด JWT มาตรฐานใด ๆ เช่นหนึ่งพบได้ที่ jwt.io สร้าง JWT ที่มีส่วนหัวและส่วนของข้อมูลเช่นตัวอย่างต่อไปนี้:
    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "abcdef1234567890"
    }
    .
    {
      "iss": "123456-compute@developer.gserviceaccount.com",
      "sub": "123456-compute@developer.gserviceaccount.com",
      "aud": "https://firestore.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600
    }
    • สำหรับ kid ฟิลด์ในส่วนหัวระบุรหัสคีย์บัญชีผู้ใช้บริการของเอกชน คุณสามารถค้นหาค่านี้ใน private_key_id ด้านการบริการไฟล์ JSON บัญชีของคุณ
    • สำหรับ iss และ sub สาขาที่ระบุที่อยู่อีเมลของบัญชีผู้ใช้บริการของคุณ คุณสามารถค้นหาค่านี้ใน client_email ด้านการบริการไฟล์ JSON บัญชีของคุณ
    • สำหรับ aud ฟิลด์ระบุปลายทางของ API ตัวอย่างเช่น: https:// SERVICE .googleapis.com/ /
    • สำหรับ iat ฟิลด์ระบุเวลา Unix ปัจจุบันและสำหรับ exp ภาคสนามระบุเวลาว่า 3600 วินาทีต่อมาเมื่อ JWT จะหมดอายุ

ลงชื่อ JWT ด้วย RSA-256 โดยใช้คีย์ส่วนตัวที่พบในไฟล์ JSON ของบัญชีบริการ

ตัวอย่างเช่น:

Java

ใช้ google-API-Java ลูกค้า และ Java-JWT :

GoogleCredential credential =
        GoogleCredential.fromStream(new FileInputStream("MyProject-1234.json"));
PrivateKey privateKey = credential.getServiceAccountPrivateKey();
String privateKeyId = credential.getServiceAccountPrivateKeyId();

long now = System.currentTimeMillis();

try {
    Algorithm algorithm = Algorithm.RSA256(null, privateKey);
    String signedJwt = JWT.create()
        .withKeyId(privateKeyId)
        .withIssuer("123456-compute@developer.gserviceaccount.com")
        .withSubject("123456-compute@developer.gserviceaccount.com")
        .withAudience("https://firestore.googleapis.com/")
        .withIssuedAt(new Date(now))
        .withExpiresAt(new Date(now + 3600 * 1000L))
        .sign(algorithm);
} catch ...

Python

ใช้ PyJWT :

iat = time.time()
exp = iat + 3600
payload = {'iss': '123456-compute@developer.gserviceaccount.com',
           'sub': '123456-compute@developer.gserviceaccount.com',
           'aud': 'https://firestore.googleapis.com/',
           'iat': iat,
           'exp': exp}
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
signed_jwt = jwt.encode(payload, PRIVATE_KEY_FROM_JSON, headers=additional_headers,
                       algorithm='RS256')
  1. โทร API ที่ใช้ลงนาม JWT เป็นผู้ถือ token:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com