如何處理精細的權限

總覽

透過精細的權限,消費者可以更精細地控管哪些帳戶資料 選擇與各個應用程式分享可讓使用者和開發人員 掌控度、透明度和安全性本指南將協助您瞭解 能夠成功更新應用程式,以處理精細的權限。

什麼是精細權限?

假設您開發的效率提升應用程式,同時要求電子郵件和日曆範圍的資訊。您的使用者 您可能只想使用應用程式存取 Google 日曆,而非 Gmail。使用精細 OAuth 使用者可選擇只授予 Google 日曆權限,無法授予 Gmail 權限。 讓使用者授予特定資料的存取權,可盡量減少資料外洩情形、提升信任度,並讓使用者以隱私權為優先,掌控自己的數位生活。請務必 設計應用程式以因應此類情況

要求多個非登入範圍時

登入和非登入範圍

如果應用程式要求登入和非登入範圍,使用者會先看到同意聲明 「登入範圍」頁面 (emailprofileopenid)。使用者同意 使用者分享基本識別資訊 (姓名、電子郵件地址和個人資料相片),就會看到 針對非登入範圍顯示精細的權限同意畫面。在這個範例中 必須檢查使用者授予哪些範圍,且無法假設使用者將權限授予所有要求 範圍。在以下範例中,網頁應用程式要求全部三個登入範圍, Google 雲端硬碟非登入範圍。使用者同意登入範圍後,系統會顯示 Google 雲端硬碟權限的細項權限同意聲明畫面:

登入和非登入範圍

多個非登入範圍

當應用程式要求多個非登入範圍時,系統會向使用者顯示精細的權限同意畫面。使用者可以選取要授予應用程式的權限。以下是要求精細權限同意畫面的範例 存取使用者的 Gmail 郵件和 Google 日曆資料:

多個非登入範圍

僅適用於要求登入 範圍 (emailprofileopenid),精細程度 權限同意畫面不適用。使用者核准或拒絕所有登入要求 請求。也就是說,如果應用程式只要求登入範圍 (一個、兩個或全部) 則不適用精細權限同意畫面

如果應用程式只要求「一個」非登入範圍, 權限同意畫面不適用。也就是說,使用者採用 拒絕整個要求,而且同意畫面中沒有核取方塊。下表 權限同意畫面顯示時的摘要。

登入範圍數量 非登入範圍數量 精細權限同意畫面
1-3 0 不適用
1-3 1+ 支援
0 1 不適用
0 2+ 支援

判斷應用程式是否受到影響

徹底檢查申請書中的所有部分, Google OAuth 2.0 授權端點可用於權限要求。請留意 在啟用精細權限同意畫面時,要求多個範圍的使用者 並未顯示給使用者在這種情況下,請務必確保程式碼可處理使用者只授權部分範圍的情況。

如何判斷應用程式是否使用多個範圍

檢查應用程式程式碼撥出網路電話,判斷 Google OAuth 2.0 應用程式提出的授權要求會導致精細的權限同意畫面 顯示。

檢查應用程式程式碼

檢查您要呼叫 Google OAuth 的應用程式程式碼的各個部分 授權端點向使用者要求權限。如果您使用 Google API 用戶端程式庫,通常可以在用戶端程式初始化步驟中找到應用程式要求的範圍。請參閱下一節中的部分範例。您應參閱應用程式用來處理 Google OAuth 2.0 的 SDK 說明文件,以便判斷應用程式是否受到影響,並參考以下範例中的指引。

Google Identity 服務

下列 Google Identity 服務 JavaScript 程式庫程式碼片段會使用多個非登入範圍,初始化 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 參數包含兩個非登入範圍。當使用者連上網路時,系統會顯示精細的權限同意畫面 應用程式向使用者要求授權。

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 參數包含兩個非登入範圍。網頁應用程式會在顯示權限要求時顯示精細的權限同意畫面 向使用者要求授權。

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 above.
    * 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
});

檢查撥出網路通話

檢查網路呼叫的方法會因您的 應用程式用戶端類型

檢查網路呼叫時,尋找傳送至 Google OAuth 的要求 授權端點並檢查 scope 參數。

這些值會導致顯示精細的同意畫面。

  • scope 參數包含登入範圍和非登入範圍。

    以下要求範例包含全部三個登入範圍,以及一個非登入範圍 如何查看使用者的 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 參數包含多個非登入範圍。

    以下要求範例包含兩個非登入範圍,可查看使用者的 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 應用程式

請參閱您用於與 Google OAuth 2.0 和 Google OAuth 2.0 互動的 SDK 文件 更新應用程式,以便根據 最佳做法

如果您使用 auth.api.signin Play 服務的 SDK 來與 Google OAuth 2.0 互動,您可以使用 requestPermissions敬上 函式用於要求所需的最小範圍組合hasPermissions 函式檢查, 來要求精細的權限

Chrome 擴充功能應用程式

應使用 Chrome Identity API:根據不同的架構與 Google OAuth 2.0 搭配使用 最佳做法

以下範例說明如何正確處理精細權限。

manifest.json

這個資訊清單檔案範例為 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"]
  }
}

錯誤做法

全部或不要

使用者按一下按鈕即可啟動授權程序。程式碼片段假設使用者會針對 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.
            ...
          }
      });
});

正確做法

最小範圍

請選取所需的最小範圍組合

應用程式只能要求所需的最小範圍組合。建議 應用程式會在需要完成工作時,一次要求一個範圍。

在這個範例中,我們假設 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 應用程式

請參閱您用於與 Google OAuth 2.0 和 Google OAuth 2.0 互動的 SDK 文件 更新應用程式,以便根據 最佳做法

如果您使用 iOS 和 macOS 版 Google 登入程式庫 來操作 Google OAuth 2.0,請參閱 精細程度處理方式說明文件 授予其要求的權限。

網頁應用程式

請參閱您用於與 Google OAuth 2.0 和 Google OAuth 2.0 互動的 SDK 文件 更新應用程式,以便根據 最佳做法

伺服器端 (離線) 存取

如要使用伺服器端 (離線) 存取模式,您必須執行下列操作:
  • 啟動伺服器並定義可公開存取的端點,以接收授權 再也不是件繁重乏味的工作
  • 設定 將用戶端的 URI 重新導向 Credentials page Google Cloud 控制台

以下程式碼片段顯示 NodeJS 範例要求兩個非登入範圍。使用者將會 請參閱精細權限同意畫面

不正確的做法

全部或不要

系統會將使用者重新導向至授權網址。程式碼片段會假設 有「完全或不指定」的提醒定義畫面上的兩個指定範圍的同意畫面 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 above
  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 Google OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from Google OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google OAuth 2.0 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);
}
正確做法

最小範圍

選取所需的最低權限範圍

應用程式只能要求所需的最小範圍組合。建議 應用程式會在需要完成工作時,一次要求一個範圍。 每當應用程式要求範圍時,應使用 漸進式授權 不必管理多個存取權杖

如果您的應用程式必須要求多個非登入範圍,建議您一律使用 漸進式授權 要求及查看使用者授予哪些範圍時。

在這個例子中,假設應用程式需要聲明的兩個範圍,才能 功能正常運作您應選擇採用 啟用精細權限設定,方便使用者進一步控管授予 應用程式。您的應用程式應檢查 已授權存取的範圍

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 above
  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 Google OAuth 2.0 server.
    if (req.url == '/') {
      res.writeHead(301, { "Location": authorizationUrl });
    }
    // Receive the callback from Google OAuth 2.0 server.
    if (req.url.startsWith('/oauth2callback')) {
      // Handle the Google OAuth 2.0 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。

僅限用戶端存取權

  • 適用於使用 Google Identity 服務的應用程式 與 Google OAuth 2.0 互動的 JavaScript 程式庫,請檢閱 說明文件 瞭解如何處理精細權限
  • 適用於直接使用 JavaScript 呼叫 Google OAuth 2.0 授權的應用程式 端點,建議您查看 說明文件 瞭解如何處理精細權限

測試更新過的應用程式,瞭解處理精細權限的情況

  1. 列出使用者可以回應權限要求的所有情況,以及應用程式預期的行為。例如,如果使用者只授權 在三個要求的範圍中,您的應用程式應採取相應行為。
  2. 請在啟用精細權限的情況下測試應用程式。啟用精細權限的方式有兩種:
    1. 此外,也請查看應用程式的 OAuth 2.0 同意畫面,確認是否顯示 應用程式已啟用精細權限, 應用程式。您也可以建立新的網路、Android 或 iOS Google OAuth 2.0 用戶端 ID 也能使用 Google Cloud 控制台進行測試
    2. 呼叫 Google OAuth 授權端點時,請將參數 enable_granular_consent 設為 true。部分 SDK 會明確支援這項功能 參數。其他情況請參閱說明文件,瞭解如何新增這個參數 手動定義。 如果導入選項不支援新增參數,您可以建立新網頁 透過 Google Cloud 控制台使用 Android 或 iOS Google OAuth 2.0 用戶端 ID 進行測試 。
  3. 測試更新後的應用程式時,請使用個人 Google 帳戶 (@gmail.com),而非 Workspace 帳戶。這是因為 Workspace Enterprise 應用程式 全網域授權委派或標示為 可信任 ,目前不受精細權限的變更影響。因此,使用 Workspace 進行測試 帳戶可能無法正常顯示新的精細同意畫面。