วิธีจัดการสิทธิ์แบบละเอียด

ภาพรวม

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

สิทธิ์แบบละเอียดคืออะไร

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

เมื่อมีการขอขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้มากกว่า 1 รายการ

ขอบเขตการลงชื่อเข้าใช้และขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้

สำหรับแอปพลิเคชันที่ขอทั้งขอบเขตการลงชื่อเข้าใช้และขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ ผู้ใช้จะเห็นหน้าความยินยอมสำหรับขอบเขตการลงชื่อเข้าใช้ก่อน (email, profile และ openid) หลังจากผู้ใช้ยินยอมที่จะแชร์ข้อมูลระบุตัวตนพื้นฐาน (ชื่อ อีเมล และรูปโปรไฟล์) ผู้ใช้จะเห็นหน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียดสำหรับขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ ในกรณีนี้ แอปพลิเคชันต้องตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์ และไม่สามารถถือว่าผู้ใช้ให้สิทธิ์ขอบเขตที่ขอทั้งหมด ในตัวอย่างต่อไปนี้ เว็บแอปพลิเคชันจะขอขอบเขตการลงชื่อเข้าใช้ทั้ง 3 รายการและขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ของ Google ไดรฟ์ หลังจากผู้ใช้ให้ความยินยอมสำหรับขอบเขตการลงชื่อเข้าใช้ ผู้ใช้จะเห็นหน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียดสำหรับสิทธิ์ Google ไดรฟ์ ดังนี้

ขอบเขตการลงชื่อเข้าใช้และขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้

ขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้มากกว่า 1 รายการ

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

ขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้มากกว่า 1 รายการ

สำหรับแอปพลิเคชันที่ขอเฉพาะขอบเขตการลงชื่อเข้าใช้ (email, profile และ openid) หน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียดจะไม่มีผล ผู้ใช้จะอนุมัติหรือปฏิเสธคำขอลงชื่อเข้าใช้ทั้งหมด กล่าวคือ หากแอปพลิเคชันขอเฉพาะขอบเขตการลงชื่อเข้าใช้ (1, 2 หรือทั้ง 3 ขอบเขต) หน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียดจะไม่เกี่ยวข้อง

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

จำนวนขอบเขตการลงชื่อเข้าใช้ จำนวนขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ หน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียด
1-3 0 ไม่เกี่ยวข้อง
1-3 1+ เกี่ยวข้อง
0 1 ไม่เกี่ยวข้อง
0 2+ เกี่ยวข้อง

ตรวจสอบว่าแอปพลิเคชันของคุณได้รับผลกระทบหรือไม่

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

วิธีตรวจสอบว่าแอปพลิเคชันของคุณใช้ขอบเขตหลายรายการหรือไม่

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

ตรวจสอบโค้ดของแอปพลิเคชัน

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

Google Identity Services

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

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly \
  https://www.googleapis.com/auth/contacts.readonly',
  callback: (response) => {
    ...
  },
});

Python

ข้อมูลโค้ดต่อไปนี้ใช้โมดูล google-auth-oauthlib.flow เพื่อสร้างคำขอการให้สิทธิ์ พารามิเตอร์ scope มีขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ 2 ขอบเขต หน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียดจะแสดงขึ้นเมื่อเว็บแอปพลิเคชันขอสิทธิ์จากผู้ใช้

import google.oauth2.credentials
import google_auth_oauthlib.flow

# Use the client_secret.json file to identify the application requesting
# authorization. The client ID (from that file) and access scopes are
# required.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
    'client_secret.json',
    scopes=[
        'https://www.googleapis.com/auth/calendar.readonly',
        'https://www.googleapis.com/auth/contacts.readonly'
    ])

Node.js

ข้อมูลโค้ดต่อไปนี้จะสร้างออบเจ็กต์ google.auth.OAuth2 ซึ่งกำหนดพารามิเตอร์ในคำขอการให้สิทธิ์ซึ่งพารามิเตอร์ scope มีขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ 2 ขอบเขต หน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียดจะแสดงขึ้นเมื่อเว็บแอปขอสิทธิ์จากผู้ใช้

const {google} = require('googleapis');

/**
  * To use OAuth2 authentication, we need access to a CLIENT_ID,
  * CLIENT_SECRET, AND REDIRECT_URI from the client_secret.json file. To get
  * these credentials for your application, visit
  * https://console.cloud.google.com/apis/credentials.
  */
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for read-only Calendar and Contacts.
const scopes = [
  'https://www.googleapis.com/auth/calendar.readonly',
  'https://www.googleapis.com/auth/contacts.readonly']
];

// Generate a url that asks permissions
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  /** Pass in the scopes array defined earlier.
    * Alternatively, if only one scope is needed, you can pass a scope URL
    * as a string */
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true
});

ตรวจสอบการเรียกใช้เครือข่ายขาออก

วิธีการตรวจสอบการเรียกใช้เครือข่ายจะแตกต่างกันไปตามประเภทแอปพลิเคชัน

ขณะตรวจสอบการเรียกใช้เครือข่าย ให้มองหาคำขอที่ส่งไปยังปลายทางการให้สิทธิ์ OAuth ของ Google และตรวจสอบพารามิเตอร์ scope

ค่าเหล่านี้ทำให้หน้าจอขอความยินยอมสำหรับสิทธิ์แบบละเอียดแสดงขึ้น

  • พารามิเตอร์ scope มีขอบเขตการลงชื่อเข้าใช้และขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้

    ตัวอย่างคำขอต่อไปนี้มีขอบเขตการลงชื่อเข้าใช้ทั้ง 3 ขอบเขตและขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ 1 ขอบเขตเพื่อดูข้อมูลเมตาของไฟล์ Google ไดรฟ์ของผู้ใช้

    https://accounts.google.com/o/oauth2/v2/auth?
    access_type=offline&
    scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
    include_granted_scopes=true&
    response_type=code&
    redirect_uri=YOUR_REDIRECT_URL&
    client_id=YOUR_CLIENT_ID
  • พารามิเตอร์ scope มีขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้มากกว่า 1 รายการ

    ตัวอย่างคำขอต่อไปนี้มีขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ 2 รายการเพื่อดูข้อมูลเมตาใน Google ไดรฟ์ของผู้ใช้และจัดการไฟล์ Google ไดรฟ์ที่เฉพาะเจาะจง

    https://accounts.google.com/o/oauth2/v2/auth?
    access_type=offline&
    scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file&
    include_granted_scopes=true&
    response_type=code&
    redirect_uri=YOUR_REDIRECT_URL&
    client_id=YOUR_CLIENT_ID

แนวทางปฏิบัติแนะนำในการจัดการสิทธิ์แบบละเอียด

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

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

อัปเดตแอปพลิเคชันเพื่อจัดการสิทธิ์แบบละเอียด

แอปพลิเคชัน Android

คุณควรดูเอกสารประกอบของ SDK ที่ใช้เพื่อโต้ตอบกับ Google OAuth 2.0 และอัปเดตแอปพลิเคชันเพื่อจัดการสิทธิ์แบบละเอียดตามแนวทางปฏิบัติแนะนำ

หากคุณใช้ SDK auth.api.signin จากบริการ Google Play เพื่อโต้ตอบกับ Google OAuth 2.0 คุณสามารถใช้ฟังก์ชัน requestPermissions เพื่อขอชุดขอบเขตที่เล็กที่สุดที่จำเป็น และใช้ฟังก์ชัน hasPermissions เพื่อตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์เมื่อขอสิทธิ์แบบละเอียด

แอปพลิเคชันส่วนขยาย Chrome

คุณควรใช้ Chrome Identity API เพื่อทำงานกับ Google OAuth 2.0 ตามแนวทางปฏิบัติแนะนำ

ตัวอย่างต่อไปนี้แสดงวิธีจัดการสิทธิ์แบบละเอียดอย่างเหมาะสม

manifest.json

ไฟล์ Manifest ตัวอย่างจะประกาศขอบเขตที่ไม่ใช่การลงชื่อเข้าใช้ 2 รายการสำหรับแอปพลิเคชันส่วนขยาย Chrome

{
  "name": "Example Chrome extension application",
  ...
  "permissions": [
      "identity"
    ],
  "oauth2" : {
      "client_id": "YOUR_CLIENT_ID",
      "scopes":[
        "https://www.googleapis.com/auth/calendar.readonly",
        "https://www.googleapis.com/auth/contacts.readonly"
      ]
  }
}

แนวทางที่ไม่ถูกต้อง

ทั้งหมดหรือไม่มีเลย

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

oauth.js

...
document.querySelector('button').addEventListener('click', function () {
  chrome.identity.getAuthToken({ interactive: true },
      function (token) {
          if (token === undefined) {
            // User didn't authorize both scopes.
            // Updating the UX and application accordingly
            ...
          } else {
            // User authorized both or one of the scopes.
            // It neglects to check which scopes users granted and assumes
            // users granted all scopes.

            // Calling the APIs, etc.
            ...
          }
      });
});

แนวทางที่ถูกต้อง

ขอบเขตที่เล็กที่สุด

เลือกชุดขอบเขตที่เล็กที่สุดที่จำเป็น

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

ในตัวอย่างนี้ ระบบจะถือว่าขอบเขตทั้ง 2 รายการที่ประกาศในไฟล์ manifest.json เป็นชุดขอบเขตที่เล็กที่สุดที่จำเป็น ไฟล์ oauth.js ใช้ Chrome Identity API เพื่อเริ่มกระบวนการให้สิทธิ์กับ Google คุณควรเลือกใช้เพื่อเปิดใช้สิทธิ์แบบละเอียด เพื่อให้ผู้ใช้ควบคุมการให้สิทธิ์แก่แอปพลิเคชันของคุณได้มากขึ้น แอปพลิเคชันของคุณควรจัดการการตอบกลับจากผู้ใช้อย่างเหมาะสมโดยตรวจสอบขอบเขตที่ผู้ใช้อนุญาต

oauth.js

...
document.querySelector('button').addEventListener('click', function () {
  chrome.identity.getAuthToken(
      { interactive: true, enableGranularPermissions: true },
      function (token, grantedScopes) {
          if (token === undefined) {
            // User didn't authorize any scope.
            // Updating the UX and application accordingly
            ...
          } else {
            // User authorized the request. Now, check which scopes were
            // granted.
            if (grantedScopes.includes(
                'https://www.googleapis.com/auth/calendar.readonly'))
            {
              // User authorized Calendar read permission.
              // Calling the APIs, etc.
              ...
            }
            else
            {
              // User didn't authorize Calendar read permission.
              // Update UX and application accordingly
              ...
            }

            if (grantedScopes.includes(
                'https://www.googleapis.com/auth/contacts.readonly'))
            {
              // User authorized Contacts read permission.
              // Calling the APIs, etc.
              ...
            }
            else
            {
              // User didn't authorize Contacts read permission.
              // Update UX and application accordingly
              ...
            }
          }
      });
});

แอปพลิเคชัน iOS, iPadOS และ macOS

คุณควรดูเอกสารประกอบของ SDK ที่ใช้เพื่อโต้ตอบกับ Google OAuth 2.0 และอัปเดตแอปพลิเคชันเพื่อจัดการสิทธิ์แบบละเอียดตามแนวทางปฏิบัติแนะนำ

หากคุณใช้ไลบรารีGoogle Sign-In สำหรับ iOS และ macOS เพื่อโต้ตอบกับ Google OAuth 2.0 คุณควรอ่านเอกสารประกอบเกี่ยวกับการจัดการสิทธิ์แบบละเอียด

เว็บแอปพลิเคชัน

คุณควรดูเอกสารประกอบของ SDK ที่ใช้เพื่อโต้ตอบกับ Google OAuth 2.0 และอัปเดตแอปพลิเคชันเพื่อจัดการสิทธิ์แบบละเอียดตามแนวทางปฏิบัติแนะนำ

การเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์)

โหมดการเข้าถึงฝั่งเซิร์ฟเวอร์ (ออฟไลน์) กำหนดให้คุณต้องทำดังนี้

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

แนวทางที่ไม่ถูกต้อง

ทั้งหมดหรือไม่มีเลย

ระบบจะเปลี่ยนเส้นทางผู้ใช้ไปยัง URL การให้สิทธิ์ ข้อมูลโค้ดจะถือว่าผู้ใช้เห็นหน้าจอขอความยินยอมแบบ "ทั้งหมดหรือไม่เลย" สำหรับขอบเขต 2 รายการที่ระบุไว้ในอาร์เรย์ scopes แต่ไม่ได้ตรวจสอบขอบเขตที่ผู้ใช้ให้สิทธิ์

main.js

...
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes - Google Calendar and Contacts
const scopes = [
  'https://www.googleapis.com/auth/contacts.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a url that asks permissions for the Google Calendar and Contacts
// scopes
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  // Pass in the scopes array defined earlier
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true
});

async function main() {
  const server = http.createServer(async function (req, res) {
    // Example on redirecting user to the Google authorization server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from the Google authorization server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google authorization server response
      let q = url.parse(req.url, true).query;

      if (q.error) {
        // User didn't authorize both scopes.
        // Updating the UX and application accordingly
        ...
      } else {
        // User authorized both or one of the scopes.
        // It neglects to check which scopes users granted and assumes users
        // granted all scopes.

        // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        // Calling the APIs, etc.
        ...
      }
    }
    res.end();
  }).listen(80);
}
แนวทางที่ถูกต้อง

ขอบเขตที่เล็กที่สุด

เลือกชุดขอบเขตที่เล็กที่สุดที่จำเป็น

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

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

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

main.js

...
const oauth2Client = new google.auth.OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);

// Access scopes for two non-Sign-In scopes - Google Calendar and Contacts
const scopes = [
  'https://www.googleapis.com/auth/contacts.readonly',
  'https://www.googleapis.com/auth/calendar.readonly'
];

// Generate a url that asks permissions for the Google Calendar and Contacts
// scopes
const authorizationUrl = oauth2Client.generateAuthUrl({
  // 'online' (default) or 'offline' (gets refresh_token)
  access_type: 'offline',
  // Pass in the scopes array defined earlier
  scope: scopes,
  // Enable incremental authorization. Recommended as best practices.
  include_granted_scopes: true,
  // Set to true to enable more granular permissions for Google OAuth 2.0
  // client IDs created before 2019. No effect for newer Google OAuth 2.0
  // client IDs, since more granular permissions is always enabled for them.
  enable_granular_consent: true
});

async function main() {
  const server = http.createServer(async function (req, res) {
    // Redirect users to the Google authorization server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from the Google authorization server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google authorization server response
      let q = url.parse(req.url, true).query;

      if (q.error) {
        // User didn't authorize both scopes.
        // Updating the UX and application accordingly
        ...
      } else {
        // Get access and refresh tokens (if access_type is offline)
        let { tokens } = await oauth2Client.getToken(q.code);
        oauth2Client.setCredentials(tokens);

        // User authorized the request. Now, check which scopes were
        // granted.
        if (tokens.scope.includes(
            'https://www.googleapis.com/auth/calendar.readonly'))
        {
          // User authorized Calendar read permission.
          // Calling the APIs, etc.
          ...
        }
        else
        {
          // User didn't authorize Calendar read permission.
          // Calling the APIs, etc.
          ...
        }

        // Check which scopes user granted the permission to application
        if (tokens.scope.includes(
            'https://www.googleapis.com/auth/contacts.readonly'))
        {
          // User authorized Contacts read permission.
          // Calling the APIs, etc.
          ...
        }
        else
        {
          // User didn't authorize Contacts read permission.
          // Update UX and application accordingly
          ...
        }
      }
    }
    res.end();
  }).listen(80);
}

ดูคู่มือเว็บแอปฝั่งเซิร์ฟเวอร์เกี่ยวกับวิธีเข้าถึง Google API จากแอปพลิเคชันที่ใช้เซิร์ฟเวอร์

สิทธิ์เข้าถึงฝั่งไคลเอ็นต์เท่านั้น

  • สำหรับแอปพลิเคชันที่ใช้ไลบรารี JavaScript ของ Google Identity Services เพื่อโต้ตอบกับ Google OAuth 2.0 คุณควรอ่านเอกสารประกอบนี้เกี่ยวกับการจัดการสิทธิ์แบบละเอียด
  • สำหรับแอปพลิเคชันที่ทำการเรียกโดยตรงโดยใช้ JavaScript ไปยังปลายทางการให้สิทธิ์ OAuth 2.0 ของ Google คุณควรตรวจสอบเอกสารประกอบนี้เกี่ยวกับการจัดการสิทธิ์แบบละเอียด

ทดสอบแอปพลิเคชันที่อัปเดตแล้วเกี่ยวกับการจัดการสิทธิ์แบบละเอียด

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

    1. ตรวจสอบหน้าจอขอความยินยอม OAuth 2.0 ของแอปพลิเคชันเพื่อดูว่ามีการเปิดใช้สิทธิ์แบบละเอียดสำหรับแอปพลิเคชันแล้วหรือยัง นอกจากนี้ คุณยังสร้างรหัสไคลเอ็นต์ OAuth 2.0 ของ Google สำหรับเว็บ, Android หรือ iOS ใหม่ผ่านคอนโซล Google Cloud เพื่อวัตถุประสงค์ในการทดสอบได้ด้วย เนื่องจากรหัสไคลเอ็นต์เหล่านี้จะเปิดใช้สิทธิ์แบบละเอียดเสมอ
    2. ตั้งค่าพารามิเตอร์ enable_granular_consent เป็น true เมื่อเรียกใช้ปลายทางการให้สิทธิ์ OAuth ของ Google SDK บางรายการรองรับพารามิเตอร์นี้อย่างชัดเจน สำหรับแพลตฟอร์มอื่นๆ โปรดดูเอกสารประกอบเพื่อดูวิธีเพิ่มพารามิเตอร์นี้และค่าของพารามิเตอร์ด้วยตนเอง หากการติดตั้งใช้งานไม่รองรับการเพิ่มพารามิเตอร์ คุณสามารถสร้างรหัสไคลเอ็นต์ Google OAuth 2.0 ใหม่สำหรับเว็บ, Android หรือ iOS ผ่านคอนโซล Google Cloud เพื่อวัตถุประสงค์ในการทดสอบเท่านั้นตามที่ระบุไว้ในข้อก่อนหน้า

  3. เมื่อทดสอบแอปพลิเคชันที่อัปเดตแล้ว ให้ใช้บัญชี Google ส่วนบุคคล (@gmail.com) แทนบัญชี Workspace เนื่องจากแอป Workspace Enterprise ที่มีการมอบสิทธิ์ระดับโดเมนหรือทำเครื่องหมายเป็นเชื่อถือได้จะไม่ได้รับผลกระทบจากการเปลี่ยนแปลงสิทธิ์แบบละเอียดในขณะนี้ ดังนั้น การทดสอบด้วยบัญชี Workspace จากองค์กรของคุณอาจไม่แสดงหน้าจอขอความยินยอมแบบละเอียดใหม่ตามที่ต้องการ