Google致力於提高黑人社區的種族平等。 怎麼看。
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

適用於客戶端Web應用程序的OAuth 2.0

本文檔說明瞭如何實施OAuth 2.0授權以從JavaScript Web應用程序訪問Google API。 OAuth 2.0允許用戶與應用程序共享特定數據,同時將用戶名,密碼和其他信息保密。例如,應用程序可以使用OAuth 2.0獲得用戶的許可,以將文件存儲在其Google雲端硬盤中。

此OAuth 2.0流稱為隱式授予流。它是為僅在用戶出現在應用程序中時才訪問API的應用程序而設計的。這些應用程序無法存儲機密信息。

在此流程中,您的應用將打開一個Google URL,該URL使用查詢參數來識別您的應用以及該應用所需的API訪問類型。您可以在當前瀏覽器窗口或彈出窗口中打開URL。用戶可以向Google進行身份驗證並授予所請求的權限。然後,Google將用戶重定向回您的應用。重定向包含一個訪問令牌,您的應用程序將對其進行驗證,然後將其用於發出API請求。

先決條件

為您的項目啟用API

任何調用Google API的應用程序都需要在API Console中啟用這些API。

為您的項目啟用API:

  1. Google API Console中的Open the API Library
  2. If prompted, select a project, or create a new one.
  3. API Library列出了所有可用的API,並按產品系列和受歡迎程度分組。如果您要啟用的API在列表中不可見,請使用搜索找到它,或單擊其所屬產品系列中的“查看全部”。
  4. 選擇要啟用的API,然後單擊“啟用”按鈕。
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

創建授權憑證

使用OAuth 2.0訪問Google API的任何應用程序都必須具有授權憑據,以將應用程序標識到Google的OAuth 2.0服務器。以下步驟說明瞭如何為您的項目創建憑據。然後,您的應用程序可以使用憑據來訪問為該項目啟用的API。

  1. Go to the Credentials page.
  2. 點擊創建憑據> OAuth客戶端ID
  3. 選擇Web應用程序應用程序類型。
  4. 完成表格。使用JavaScript發出授權的Google API請求的應用程序必須指定授權的JavaScript來源。來源標識您的應用程序可以從中向OAuth 2.0服務器發送請求的域。這些來源必須遵守Google的驗證規則

確定訪問範圍

範圍使您的應用程序僅可以請求訪問其所需的資源,同時還使用戶能夠控制他們授予您的應用程序的訪問量。因此,請求的範圍數與獲得用戶同意的可能性之間可能存在反比關係。

在開始實施OAuth 2.0授權之前,我們建議您確定您的應用需要訪問權限的範圍。

OAuth 2.0 API範圍文檔包含您可以用來訪問Google API的範圍的完整列表。

獲取OAuth 2.0訪問令牌

以下步驟顯示了您的應用程序如何與Google的OAuth 2.0服務器進行交互以獲取用戶的同意,以代表用戶執行API請求。您的應用必須先獲得同意,然後才能執行需要用戶授權的Google API請求。

步驟1:配置客戶端對象

如果您正在使用JavaScript的Google API客戶端庫來處理OAuth 2.0流,那麼第一步就是配置gapi.auth2gapi.client對象。這些對象使您的應用程序可以獲得用戶授權並發出授權的API請求。

客戶端對象標識您的應用程序正在請求訪問權限的範圍。這些值將告知Google向用戶顯示的同意屏幕。

JS客戶端庫

JavaScript客戶端庫簡化了授權過程的許多方面:

  1. 它為Google的授權服務器創建重定向URL,並提供一種將用戶定向到該URL的方法。
  2. 它處理從該服務器到應用程序的重定向。
  3. 它驗證授權服務器返回的訪問令牌。
  4. 它存儲授權服務器發送給您的應用程序的訪問令牌,並在您的應用程序隨後進行授權的API調用時進行檢索。

下面的代碼段摘自本文檔後面顯示的完整示例。這段代碼初始化了gapi.client對象,您的應用程序以後將使用該對象來進行API調用。創建該對象時,您的應用程序用來檢查和監視用戶授權狀態的gapi.auth2gapi.auth2也會被初始化。

gapi.client.init的調用指定以下字段:

  • apiKeyclientId值指定您的應用程序的授權憑證。如創建授權憑證部分中所述,可以在API Console中獲得這些值。請注意,如果您的應用程序發出了授權的API請求,則clientId是必需的。僅發出未授權請求的應用程序可以僅指定API密鑰。
  • scope字段指定以空格分隔的訪問範圍列表,這些訪問範圍與應用程序可以代表用戶訪問的資源相對應。這些值將告知Google向用戶顯示的同意屏幕。

    我們建議您的應用程序盡可能請求在上下文中訪問授權範圍。通過使用增量授權在上下文中請求訪問用戶數據,可以幫助用戶更輕鬆地理解應用程序為何需要其所請求的訪問權限。

  • discoveryDocs字段標識您的應用程序使用的API Discovery文檔的列表。 Discovery文檔描述了API的表面,包括其資源模式,並且JavaScript客戶端庫使用該信息來生成應用程序可以使用的方法。在此示例中,代碼檢索了Google Drive API版本3的發現文檔。

gapi.client.init調用完成後,代碼將設置GoogleAuth變量以標識Google Auth對象。最後,該代碼設置了一個偵聽器,該偵聽器在用戶的登錄狀態更改時調用一個函數。 (該功能未在代碼段中定義。)

var GoogleAuth; // Google Auth object.
function initClient() {
  gapi.client.init({
      'apiKey': 'YOUR_API_KEY',
      'clientId': 'YOUR_CLIENT_ID',
      'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
      'discoveryDocs': ['https://www.googleapis.com/discovery/v1/apis/drive/v3/rest']
  }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);
  });
}

OAuth 2.0端點

如果您直接訪問OAuth 2.0端點,則可以繼續執行下一步。

第2步:重定向到Google的OAuth 2.0服務器

要請求訪問用戶數據的權限,請將用戶重定向到Google的OAuth 2.0服務器。

JS客戶端庫

調用GoogleAuth.signIn()方法將用戶定向到Google的授權服務器。

GoogleAuth.signIn();

實際上,您的應用程序可能會設置一個布爾值,以確定在嘗試進行API調用之前是否調用signIn()方法。

下面的代碼段演示瞭如何啟動用戶授權流程。請注意有關代碼段的以下幾點:

  • 代碼中引用的GoogleAuth對象與步驟1中的代碼段中定義的全局變量相同。

  • updateSigninStatus函數是一個偵聽器,用於偵聽用戶授權狀態的更改。在步驟1:
    GoogleAuth.isSignedIn.listen(updateSigninStatus);
    的代碼段中還定義了其作為偵聽器的角色。
  • 該代碼段定義了兩個附加的全局變量:

    • isAuthorized是一個布爾型變量,指示用戶是否已經登錄。可以在加載應用程序時設置此值,並在用戶登錄或退出應用程序時更新該值。

      在此代碼段中, sendAuthorizedApiRequest函數檢查變量的值以確定應用程序是否應嘗試需要授權的API請求或提示用戶授權應用程序。

    • currentApiRequest是一個對象,該對象存儲有關用戶嘗試的最後一個API請求的詳細信息。當應用程序調用sendAuthorizedApiRequest函數時,將設置對象的值。

      如果用戶已授權該應用,則該請求將立即執行。否則,該函數將重定向用戶以進行登錄。用戶登錄後, updateSignInStatus函數將調用sendAuthorizedApiRequest ,並傳入與授權流開始之前嘗試的相同請求。

var isAuthorized;
var currentApiRequest;

/**
 * Store the request details. Then check to determine whether the user
 * has authorized the application.
 *   - If the user has granted access, make the API request.
 *   - If the user has not granted access, initiate the sign-in flow.
 */
function sendAuthorizedApiRequest(requestDetails) {
  currentApiRequest = requestDetails;
  if (isAuthorized) {
    // Make API request
    // gapi.client.request(requestDetails)

    // Reset currentApiRequest variable.
    currentApiRequest = {};
  } else {
    GoogleAuth.signIn();
  }
}

/**
 * Listener called when user completes auth flow. If the currentApiRequest
 * variable is set, then the user was prompted to authorize the application
 * before the request executed. In that case, proceed with that API request.
 */
function updateSigninStatus(isSignedIn) {
  if (isSignedIn) {
    isAuthorized = true;
    if (currentApiRequest) {
      sendAuthorizedApiRequest(currentApiRequest);
    }
  } else {
    isAuthorized = false;
  }
}

OAuth 2.0端點

https://accounts.google.com/o/oauth2/v2/auth生成一個URL,以請求從Google的OAuth 2.0端點進行訪問。該端點可通過HTTPS訪問;純HTTP連接被拒絕。

Google授權服務器支持Web服務器應用程序的以下查詢字符串參數:

參數
client_id必需的

您的應用程序的客戶端ID。您可以在API Console Credentials page中找到該值。

redirect_uri必需的

確定用戶完成授權流程後API服務器將用戶重定向到的位置。該值必須與您在客戶端的API Console Credentials page中配置的OAuth 2.0客戶端的授權重定向URI之一完全匹配。如果此值與提供的client_id的授權重定向URI不匹配,您將收到redirect_uri_mismatch錯誤。

請注意, httphttps方案,大小寫和斜杠(' / ')必須全部匹配。

response_type必需的

JavaScript應用程序需要將參數的值設置為token 。此值指示Google授權服務器在完成授權過程後,將用戶令牌重定向到的URI( # )的片段標識符中的name=value對形式返回訪問令牌。

scope必需的

用空格分隔的範圍列表,這些範圍標識應用程序可以代表用戶訪問的資源。這些值將告知Google向用戶顯示的同意屏幕。

範圍使您的應用程序僅可以請求訪問其所需的資源,同時還使用戶能夠控制他們授予您的應用程序的訪問量。因此,在所請求範圍的數量與獲得用戶同意的可能性之間存在反比關係。

我們建議您的應用程序盡可能請求在上下文中訪問授權範圍。通過使用增量授權在上下文中請求訪問用戶數據,可以幫助用戶更輕鬆地理解應用程序為何需要其所請求的訪問權限。

state受到推崇的

指定應用程序用來維護授權請求和授權服務器的響應之間的狀態的任何字符串值。在用戶同意或拒絕您的應用程序的訪問請求之後,服務器會在redirect_uri的URL片段標識符( # )中返回您作為name=value對發送的確切值。

您可以將此參數用於多種目的,例如將用戶定向到應用程序中的正確資源,發送隨機數以及減輕跨站點請求偽造。由於您可以猜測您的redirect_uri ,因此使用state值可以增加您對傳入連接是身份驗證請求的結果的保證。如果您生成隨機字符串或對Cookie的哈希值或其他捕獲客戶端狀態的值進行編碼,則可以驗證響應以進一步確保請求和響應源自同一瀏覽器,從而提供針對跨站點等攻擊的防護要求偽造。有關如何創建和確認state令牌的示例,請參見OpenID Connect文檔。

include_granted_scopes可選的

使應用程序能夠使用增量授權來請求訪問上下文中的其他範圍。如果將此參數的值設置為true並批准了授權請求,則新的訪問令牌還將覆蓋用戶先前已授予應用程序訪問權限的所有範圍。有關示例,請參見增量授權部分。

login_hint可選的

如果您的應用程序知道哪個用戶正在嘗試進行身份驗證,則可以使用此參數向Google身份驗證服務器提供提示。服務器通過預填寫登錄表單中的電子郵件字段或通過選擇適當的多登錄會話來使用提示來簡化登錄流程。

將參數值設置為電子郵件地址或sub標識符,與用戶的Google ID等效。

prompt可選的

以空格分隔的區分大小寫的提示列表,以提示用戶。如果您未指定此參數,則僅在您的項目第一次請求訪問時才提示用戶。有關更多信息,請參閱提示重新同意

可能的值為:

none不要顯示任何身份驗證或同意屏幕。不得與其他值一起指定。
consent提示用戶同意。
select_account提示用戶選擇一個帳戶。

樣本重定向到Google的授權服務器

下面顯示了一個示例URL,其中包含換行符和空格,以提高可讀性。

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

創建請求URL後,將用戶重定向到該URL。

JavaScript示例代碼

以下JavaScript代碼段顯示瞭如何在不使用JavaScript的Google API客戶端庫的情況下在JavaScript中啟動授權流程。由於此OAuth 2.0端點不支持跨域資源共享(CORS),因此該代碼段創建了一個表單,用於向該端點打開請求。

/*
 * Create form to request access token from Google's OAuth 2.0 server.
 */
function oauthSignIn() {
  // Google's OAuth 2.0 endpoint for requesting an access token
  var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

  // Create <form> element to submit parameters to OAuth 2.0 endpoint.
  var form = document.createElement('form');
  form.setAttribute('method', 'GET'); // Send as a GET request.
  form.setAttribute('action', oauth2Endpoint);

  // Parameters to pass to OAuth 2.0 endpoint.
  var params = {'client_id': 'YOUR_CLIENT_ID',
                'redirect_uri': 'YOUR_REDIRECT_URI',
                'response_type': 'token',
                'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                'include_granted_scopes': 'true',
                'state': 'pass-through value'};

  // Add form parameters as hidden input values.
  for (var p in params) {
    var input = document.createElement('input');
    input.setAttribute('type', 'hidden');
    input.setAttribute('name', p);
    input.setAttribute('value', params[p]);
    form.appendChild(input);
  }

  // Add form to page and submit it to open the OAuth 2.0 endpoint.
  document.body.appendChild(form);
  form.submit();
}

第3步:Google提示用戶同意

在此步驟中,用戶決定是否向您的應用程序授予所請求的訪問權限。在此階段,Google將顯示一個同意窗口,其中顯示您的應用程序的名稱以及它請求使用用戶的授權憑證進行訪問的Google API服務以及要授予的訪問範圍的摘要。然後,用戶可以同意授予對您的應用程序請求的一個或多個範圍的訪問權限,或拒絕該請求。

您的應用程序在此階段不需要執行任何操作,因為它等待來自Google的OAuth 2.0服務器的響應(指示是否已授予任何訪問權限)。該響應將在以下步驟中進行說明。

步驟4:處理OAuth 2.0服務器響應

JS客戶端庫

JavaScript客戶端庫處理來自Google授權服務器的響應。如果將偵聽器設置為監視當前用戶的登錄狀態中的更改,則在用戶授予對應用程序的請求訪問權限時,將調用該函數。

OAuth 2.0端點

OAuth 2.0服務器向您的訪問令牌請求中指定的redirect_uri發送響應。

如果用戶批准了該請求,則響應中將包含一個訪問令牌。如果用戶不同意該請求,則響應中將包含一條錯誤消息。訪問令牌或錯誤消息在重定向URI的哈希片段上返回,如下所示:

  • 訪問令牌響應:

    https://oauth2.example.com/callback#access_token=4/P7q7W91&token_type=Bearer&expires_in=3600

    除了access_token參數之外,片段字符串還包含token_type參數(始終設置為Bearer )和expires_in參數(指定令牌的生存時間,以秒為單位)。如果在訪問令牌請求中指定了state參數,則其值也將包含在響應中。

  • 錯誤響應:
    https://oauth2.example.com/callback#error=access_denied

OAuth 2.0服務器響應示例

您可以通過單擊以下示例URL來測試此流程,該示例URL要求具有隻讀訪問權限,以查看Google雲端硬盤中文件的元數據:

https://accounts.google.com/o/oauth2/v2/auth?
 scope=https%3A//www.googleapis.com/auth/drive.metadata.readonly&
 include_granted_scopes=true&
 response_type=token&
 state=state_parameter_passthrough_value&
 redirect_uri=https%3A//oauth2.example.com/code&
 client_id=client_id

完成OAuth 2.0流程後,您將被重定向到http://localhost/oauth2callback 。除非您的本地計算機碰巧在該地址提供文件,否則該URL將產生404 NOT FOUND錯誤。下一步將提供有關將用戶重定向回您的應用程序時URI中返回的信息的更多詳細信息。

調用Google API

JS客戶端庫

您的應用程序獲取訪問令牌後,可以使用JavaScript客戶端庫代表用戶發出API請求。客戶端庫為您管理訪問令牌,您無需執行任何特殊操作即可在請求中發送它。

客戶端庫支持兩種調用API方法的方法。如果您已加載發現文檔,則API將為您定義特定於方法的功能。您還可以使用gapi.client.request函數來調用API方法。以下兩個片段演示了Drive API的about.get方法的這些選項。

// Example 1: Use method-specific function
var request = gapi.client.drive.about.get({'fields': 'user'});

// Execute the API request.
request.execute(function(response) {
  console.log(response);
});


// Example 2: Use gapi.client.request(args) function
var request = gapi.client.request({
  'method': 'GET',
  'path': '/drive/v3/about',
  'params': {'fields': 'user'}
});
// Execute the API request.
request.execute(function(response) {
  console.log(response);
});

OAuth 2.0端點

您的應用程序獲取訪問令牌後,如果已授予該API所需的訪問範圍,則可以使用該令牌代表給定的用戶帳戶對Google API進行調用。為此,請通過包含access_token查詢參數或Authorization HTTP標頭Bearer值,在對API的請求中包含訪問令牌。盡可能使用HTTP標頭,因為查詢字符串在服務器日誌中趨於可見。在大多數情況下,您可以使用客戶端庫來設置對Google API的調用(例如,在調用Drive Files API時)。

您可以在OAuth 2.0 Playground試用所有Google API並查看其範圍。

HTTP GET示例

使用Authorization: Bearer HTTP標頭對drive.files端點(Drive Files API)的調用可能如下所示。請注意,您需要指定自己的訪問令牌:

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

這是使用access_token查詢字符串參數對已驗證用戶使用相同API的調用:

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

JavaScript示例代碼

下面的代碼段演示瞭如何使用CORS(跨域資源共享)向Google API發送請求。本示例未使用Google JavaScript API客戶端庫。但是,即使您沒有使用客戶端庫,該庫文檔中的CORS支持指南也可能會幫助您更好地理解這些請求。

在此代碼段中, access_token變量表示您代表授權用戶進行API請求所獲得的令牌。完整的示例演示瞭如何將該令牌存儲在瀏覽器的本地存儲中,以及在發出API請求時如何檢索該令牌。

var xhr = new XMLHttpRequest();
xhr.open('GET',
    'https://www.googleapis.com/drive/v3/about?fields=user&' +
    'access_token=' + params['access_token']);
xhr.onreadystatechange = function (e) {
  console.log(xhr.response);
};
xhr.send(null);

完整的例子

JS客戶端庫

示例代碼演示

本節包含代碼示例的工作演示,隨後將演示代碼在實際應用中的行為。授權應用程序後,該應用程序將列在與您的Google帳戶關聯應用程序中。該應用程序名為用於Google API文檔的OAuth 2.0演示。同樣,如果您撤消訪問權限並刷新該頁面,則該應用將不再列出。

請注意,此應用程序請求訪問https://www.googleapis.com/auth/drive.metadata.readonly範圍。僅要求訪問權限以演示如何在JavaScript應用程序中啟動OAuth 2.0流。此應用程序不發出任何API請求。

JavaScript示例代碼

如上所示,此代碼示例適用於一個頁面(一個應用程序),該頁面加載了JavaScript的Google API客戶端庫並啟動了OAuth 2.0流程。該頁面顯示:

  • 一個按鈕,允許用戶登錄到應用程序。如果用戶先前未授權該應用,則該應用將啟動OAuth 2.0流程。
  • 兩個按鈕,使用戶可以退出應用程序或撤消先前授予該應用程序的訪問權限。如果您退出某個應用程序,則尚未撤消授予該應用程序的訪問權限。您需要再次登錄,然後該應用程序才能代表您提出其他授權請求,但下次使用該應用程序時,您無需再次授予訪問權限。但是,如果您撤消了訪問權限,則確實需要再次授予訪問權限。

您還可以通過Google帳戶的“權限”頁面撤消對應用程序的訪問權限。該應用程序被列為Google API文檔的OAuth 2.0演示

<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }

  function initClient() {
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';

    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from API Console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'clientId': 'YOUR_CLIENT_ID',
        'discoveryDocs': [discoveryUrl],
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);

      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();

      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      });
      $('#revoke-access-button').click(function() {
        revokeAccess();
      });
    });
  }

  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked "Sign out" button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }

  function revokeAccess() {
    GoogleAuth.disconnect();
  }

  function setSigninStatus() {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');
    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }

  function updateSigninStatus() {
    setSigninStatus();
  }
</script>

<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>

<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js"
        onload="this.onload=function(){};handleClientLoad()"
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>

OAuth 2.0端點

此代碼示例演示瞭如何在不使用JavaScript的Google API客戶端庫的情況下完成JavaScript中的OAuth 2.0流。該代碼用於HTML頁面,該頁面顯示一個按鈕以嘗試API請求。如果單擊該按鈕,代碼將檢查該頁面是否已在瀏覽器的本地存儲中存儲了API訪問令牌。如果是這樣,它將執行API請求。否則,它將啟動OAuth 2.0流。

對於OAuth 2.0流程,頁面遵循以下步驟:

  1. 它將用戶定向到Google的OAuth 2.0服務器,該服務器請求訪問https://www.googleapis.com/auth/drive.metadata.readonly範圍。
  2. 在授予(或拒絕)對一個或多個請求的範圍的訪問權限之後,用戶將被重定向到原始頁面,該頁面從片段標識符字符串中解析訪問令牌。
  3. 該頁面使用訪問令牌發出示例API請求。

    API請求調用Drive API的about.get方法來檢索有關授權用戶的Google Drive帳戶的信息。

  4. 如果請求成功執行,則API響應將記錄在瀏覽器的調試控制台中。

您可以通過Google帳戶的“權限”頁面撤消對該應用程序的訪問權限。該應用程序將列為Google API文檔的OAuth 2.0演示

要在本地運行此代碼,您需要為YOUR_CLIENT_IDYOUR_REDIRECT_URI變量設置與您的授權憑證相對應的值。 YOUR_REDIRECT_URI變量應設置為提供頁面的相同URL。該值必須與您在API Console Credentials page中配置的OAuth 2.0客戶端的授權重定向URI之一完全匹配。如果此值與授權的URI不匹配,則會收到redirect_uri_mismatch錯誤。您的項目還必須為此請求啟用適當的API

<html><head></head><body>
<script>
  var YOUR_CLIENT_ID = 'REPLACE_THIS_VALUE';
  var YOUR_REDIRECT_URI = 'REPLACE_THIS_VALUE';
  var fragmentString = location.hash.substring(1);

  // Parse query string to see if page request is coming from OAuth 2.0 server.
  var params = {};
  var regex = /([^&=]+)=([^&]*)/g, m;
  while (m = regex.exec(fragmentString)) {
    params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
  }
  if (Object.keys(params).length > 0) {
    localStorage.setItem('oauth2-test-params', JSON.stringify(params) );
    if (params['state'] && params['state'] == 'try_sample_request') {
      trySampleRequest();
    }
  }

  // If there's an access token, try an API request.
  // Otherwise, start OAuth 2.0 flow.
  function trySampleRequest() {
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    if (params && params['access_token']) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET',
          'https://www.googleapis.com/drive/v3/about?fields=user&' +
          'access_token=' + params['access_token']);
      xhr.onreadystatechange = function (e) {
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.response);
        } else if (xhr.readyState === 4 && xhr.status === 401) {
          // Token invalid, so prompt for user permission.
          oauth2SignIn();
        }
      };
      xhr.send(null);
    } else {
      oauth2SignIn();
    }
  }

  /*
   * Create form to request access token from Google's OAuth 2.0 server.
   */
  function oauth2SignIn() {
    // Google's OAuth 2.0 endpoint for requesting an access token
    var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';

    // Create element to open OAuth 2.0 endpoint in new window.
    var form = document.createElement('form');
    form.setAttribute('method', 'GET'); // Send as a GET request.
    form.setAttribute('action', oauth2Endpoint);

    // Parameters to pass to OAuth 2.0 endpoint.
    var params = {'client_id': YOUR_CLIENT_ID,
                  'redirect_uri': YOUR_REDIRECT_URI,
                  'scope': 'https://www.googleapis.com/auth/drive.metadata.readonly',
                  'state': 'try_sample_request',
                  'include_granted_scopes': 'true',
                  'response_type': 'token'};

    // Add form parameters as hidden input values.
    for (var p in params) {
      var input = document.createElement('input');
      input.setAttribute('type', 'hidden');
      input.setAttribute('name', p);
      input.setAttribute('value', params[p]);
      form.appendChild(input);
    }

    // Add form to page and submit it to open the OAuth 2.0 endpoint.
    document.body.appendChild(form);
    form.submit();
  }
</script>

<button onclick="trySampleRequest();">Try sample request</button>
</body></html>

JavaScript來源驗證規則

Google將以下驗證規則應用於JavaScript來源,以幫助開發人員確保其應用程序的安全。您的JavaScript來源必須遵守這些規則。有關域,主機和方案的定義,請參閱RFC 3986第3節,如下所述。

驗證規則
方案

URI必須使用HTTPS方案,而不是純HTTP。

主持人

主機不能是原始IP地址。 Localhost IP地址不受此規則的限制。

領域
  • 主機TLD(頂級域)必須屬於公共後綴列表
  • 主機域不能為“googleusercontent.com”
  • URI不能包含URL縮短域(例如goo.gl ),除非應用擁有該域。
  • 人物URI不能包含某些字符,包括:
    • 通配符( '*'
    • 不可打印的ASCII字符
    • 無效的百分比編碼(不遵循URL編碼形式的百分比符號(後跟兩個十六進制數字的任何百分比編碼))
    • 空字符(編碼的空字符,例如%00%C0%80

    增量授權

    在OAuth 2.0協議中,您的應用請求訪問權限的授權,這些資源由作用域標識。在您需要資源時請求授權是一種最佳的用戶體驗做法。為此,Google的授權服務器支持增量授權。使用此功能,您可以根據需要請求範圍,如果用戶授予對新範圍的權限,則返回授權碼,該授權碼可以交換為包含用戶已授予項目的所有範圍的令牌。

    例如,一個使人們可以採樣音樂曲目並創建混音的應用在登錄時可能只需要很少的資源,也許只不過是登錄人員的名字而已。但是,保存完整的混音將需要訪問其Google雲端硬盤。如果只在應用實際需要時才要求他們訪問其Google雲端硬盤,大多數人會覺得很自然。

    在這種情況下,在登錄時的應用程序可能要求openidprofile範圍在登錄執行基本的,再後來要求https://www.googleapis.com/auth/drive.file在時間範圍保存混音的第一個請求。

    以下規則適用於從增量授權獲得的訪問令牌:

    • 令牌可用於訪問與合併到新的組合授權中的任何範圍相對應的資源。
    • 當您對合併的授權使用刷新令牌來獲取訪問令牌時,該訪問令牌代表合併的授權,並且可以用於響應中包含的任何scope值。
    • 組合授權包括用戶授予API項目的所有範圍,即使這些授權是從其他客戶端請求的也是如此。例如,如果用戶使用應用程序的桌面客戶端授予了對一個範圍的訪問權限,然後通過移動客戶端向同一應用程序授予了另一個範圍,則合併的授權將同時包括兩個範圍。
    • 如果您撤消代表組合授權的令牌,則代表相關用戶同時撤消對所有授權範圍的訪問。

    下面的代碼示例演示如何將範圍添加到現有的訪問令牌。這種方法使您的應用程序無需管理多個訪問令牌。

    JS客戶端庫

    要將範圍添加到現有訪問令牌中,請調用GoogleUser.grant(options)方法。 options對象標識您要授予訪問權限的其他範圍。

    // Space-separated list of additional scope(s) you are requesting access to.
    // This code adds read-only access to the user's calendars via the Calendar API.
    var NEW_SCOPES = 'https://www.googleapis.com/auth/calendar.readonly';
    
    // Retrieve the GoogleUser object for the current user.
    var GoogleUser = GoogleAuth.currentUser.get();
    GoogleUser.grant({'scope': NEW_SCOPES});

    OAuth 2.0端點

    要將範圍添加到現有訪問令牌,請在對Google OAuth 2.0服務器的請求中包括include_granted_scopes參數。

    以下代碼段演示瞭如何執行此操作。該代碼段假定您已將訪問令牌對其有效的範圍存儲在瀏覽器的本地存儲中。 (完整的示例代碼通過在瀏覽器的本地存儲中設置oauth2-test-params.scope屬性來存儲訪問令牌對其有效的作用域列表。)

    該代碼段將訪問令牌對其有效的範圍與您要用於特定查詢的範圍進行比較。如果訪問令牌不覆蓋該範圍,則OAuth 2.0流程開始。在這裡, oauth2SignIn函數與步驟2中提供的功能相同(在完整示例中稍後提供)。

    var SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly';
    var params = JSON.parse(localStorage.getItem('oauth2-test-params'));
    
    var current_scope_granted = false;
    if (params.hasOwnProperty('scope')) {
      var scopes = params['scope'].split(' ');
      for (var s = 0; s < scopes.length; s++) {
        if (SCOPE == scopes[s]) {
          current_scope_granted = true;
        }
      }
    }
    
    if (!current_scope_granted) {
      oauth2SignIn(); // This function is defined elsewhere in this document.
    } else {
      // Since you already have access, you can proceed with the API request.
    }

    吊銷令牌

    在某些情況下,用戶可能希望撤消對應用程序的訪問權限。用戶可以通過訪問“帳戶設置”來撤消訪問權限。有關更多信息,請參閱有權訪問您的帳戶支持文檔的第三方網站和應用程序的“刪除網站或應用程序訪問權限”部分

    應用程序也有可能以編程方式撤銷對它的訪問。在用戶取消訂閱,刪除應用程序或應用程序所需的API資源發生重大變化的情況下,程序吊銷非常重要。換句話說,刪除過程的一部分可以包括API請求,以確保刪除先前授予該應用程序的權限。

    JS客戶端庫

    要以編程方式撤消令牌,請調用GoogleAuth.disconnect()

    GoogleAuth.disconnect();

    OAuth 2.0端點

    要以編程方式撤消令牌,您的應用程序會向https://oauth2.googleapis.com/revoke發出請求,並將令牌作為參數包括在內:

    curl -d -X -POST --header "Content-type:application/x-www-form-urlencoded" \
            https://oauth2.googleapis.com/revoke?token={token}

    令牌可以是訪問令牌或刷新令牌。如果令牌是訪問令牌,並且具有相應的刷新令牌,則刷新令牌也將被吊銷。

    如果撤消已成功處理,則響應的HTTP狀態代碼為200 。對於錯誤情況,將返回HTTP狀態代碼400和錯誤代碼。

    以下JavaScript代碼段顯示瞭如何在不使用JavaScript的Google API客戶端庫的情況下撤銷JavaScript中的令牌。由於Google的用於吊銷令牌的OAuth 2.0端點不支持跨域資源共享(CORS),因此代碼創建了一個表單並將表單提交給端點,而不是使用XMLHttpRequest()方法來發布請求。

    function revokeAccess(accessToken) {
      // Google's OAuth 2.0 endpoint for revoking access tokens.
      var revokeTokenEndpoint = 'https://oauth2.googleapis.com/revoke';
    
      // Create <form> element to use to POST data to the OAuth 2.0 endpoint.
      var form = document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', revokeTokenEndpoint);
    
      // Add access token to the form so it is set as value of 'token' parameter.
      // This corresponds to the sample curl request, where the URL is:
      //      https://oauth2.googleapis.com/revoke?token={token}
      var tokenField = document.createElement('input');
      tokenField.setAttribute('type', 'hidden');
      tokenField.setAttribute('name', 'token');
      tokenField.setAttribute('value', accessToken);
      form.appendChild(tokenField);
    
      // Add form to page and submit it to actually revoke the token.
      document.body.appendChild(form);
      form.submit();
    }