2023-02-15 針對網絡服務器應用使用 OAuth 2.0

針對網絡服務器應用使用 OAuth 2.0

https://developers.google.com/identity/protocols/oauth2/web-server?hl=zh-cn#offline

本文檔介紹了 Web 服務器應用如何使用 Google API 客戶端庫或 Google OAuth 2.0 端點來實現 OAuth 2.0 授權以訪問 Google API。

OAuth 2.0 可讓用戶與應用共享特定數據,同時保持用戶名、密碼和其他信息的私密性。例如,應用可以使用 OAuth 2.0 向用戶請求在其 Google 云端硬盤中存儲文件的權限。

此 OAuth 2.0 流程專門用于用戶授權。它專為可以存儲機密信息并維護狀態(tài)的應用而設計。適當授權的網絡服務器應用可以在用戶與應用互動時或用戶離開應用后訪問 API。

Web 服務器應用通常還會使用服務帳號向 API 請求授權,尤其是在調用 Cloud API 來訪問基于項目的數據時,而不是訪問特定于用戶的數據時。網絡服務器應用可以將服務帳號與用戶授權結合使用。

注意:考慮到正確實現的安全性影響,我們強烈建議您在與 Google 的 OAuth 2.0 端點互動時使用 OAuth 2.0 庫。使用他人提供的經過充分調試的代碼是最佳做法,有助于保護您自己和用戶。如需了解詳情,請參閱客戶端庫

客戶端庫

本頁面上特定于語言的示例使用 Google API 客戶端庫來實現 OAuth 2.0 授權。要運行代碼示例,您必須先安裝適用于您的語言的客戶端庫。

當您使用 Google API 客戶端庫處理應用的 OAuth 2.0 流程時,客戶端庫會執(zhí)行應用需要自行處理的許多操作。例如,它會決定應用何時可以使用或刷新存儲的訪問令牌,以及應用何時必須重新征得用戶同意??蛻舳藥爝€會生成正確的重定向網址,并有助于實現使用授權代碼交換訪問令牌的重定向處理程序。

適用于服務器端應用的 Google API 客戶端庫支持以下語言:

前提條件

為您的項目啟用 API

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

如需為您的項目啟用該 API,請按以下步驟操作:

  1. Open the API Library (在 Google API Console中)。
  2. If prompted, select a project, or create a new one.
  3. API Library 列出了所有可用的 API,按產品系列和熱門程度分組。如果列表中沒有顯示您要啟用的 API,請使用搜索功能查找該 API,或點擊該 API 所屬的產品系列中的查看全部。
  4. 選擇您要啟用的 API,然后點擊啟用按鈕。
  5. If prompted, enable billing.
  6. If prompted, read and accept the API's Terms of Service.

創(chuàng)建授權憑據

任何使用 OAuth 2.0 訪問 Google API 的應用都必須使用授權憑據向 Google 的 OAuth 2.0 服務器標識該應用。以下步驟說明了如何為項目創(chuàng)建憑據。然后,您的應用可以使用這些憑據訪問為該項目啟用的 API。

  1. Go to the Credentials page.

  2. 依次點擊創(chuàng)建憑據 > OAuth 客戶端 ID。

  3. 選擇 Web 應用應用類型。

  4. 填寫表單,然后點擊創(chuàng)建。使用 PHP、Java、Python、Ruby 和 .NET 等語言和框架的應用必須指定經授權的重定向 URI。重定向 URI 是 OAuth 2.0 服務器可將響應發(fā)送到的端點。這些端點必須遵循 Google 的驗證規(guī)則

    如需進行測試,您可以指定引用本地機器的 URI,例如 http://localhost:8080。請注意這一點,請注意,本文檔中的所有示例均使用 http://localhost:8080 作為重定向 URI。

    我們建議您設計應用的身份驗證端點,使應用不會向頁面上的其他資源公開授權代碼。

創(chuàng)建憑據后,從 API Console下載 client_secret.json 文件。將文件安全地存儲在只有您的應用可以訪問的位置。

重要提示:請勿將 client_secret.json 文件存儲在可公開訪問的位置。此外,如果您與應用共享源代碼(例如,在 GitHub 上),請將 client_secret.json 文件存儲在源代碼樹之外,以避免無意中共享您的客戶端憑據。

確定訪問權限范圍

通過范圍,您的應用可以僅請求訪問所需的資源,同時還能控制用戶向您的應用授予的訪問量。因此,請求的范圍數與征得用戶同意的可能性之間可能存在逆向關系。

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

我們還建議您的應用通過增量授權流程請求對授權范圍的訪問權限,在此過程中,您的應用會在上下文中請求訪問用戶數據。此最佳做法可幫助用戶更輕松地了解應用需要其請求的訪問權限的原因。

OAuth 2.0 API 范圍文檔包含可用于訪問 Google API 的完整范圍列表。

如果您的公共應用使用了允許訪問特定用戶數據的范圍,則必須完成驗證流程。測試您的應用時,如果您在屏幕上看到未經驗證的應用,您必須提交驗證請求以將其移除。請詳細了解未經驗證的應用,并在幫助中心獲取有關應用驗證的常見問題解答

特定語言要求

要運行本文檔中的任何代碼示例,您需要擁有 Google 帳號、互聯網訪問權限和網絡瀏覽器。如果您使用的是某個 API 客戶端庫,另請參閱下文針對特定語言的要求。
獲取 OAuth 2.0 訪問令牌
以下步驟顯示了您的應用如何與 Google 的 OAuth 2.0 服務器進行交互,以獲取用戶同意代表用戶執(zhí)行 API 請求。您的應用必須先獲得用戶同意,然后才能執(zhí)行需要用戶授權的 Google API 請求。

下面的列表快速總結了這些步驟:

您的應用確定所需的權限。
您的應用會將用戶連同請求的權限列表一起重定向到 Google。
用戶決定是否向您的應用授予權限。
您的應用會查找用戶的決定。
如果用戶被授予所請求的權限,您的應用將檢索代表用戶發(fā)出 API 請求所需的令牌。

第 1 步:設置授權參數

第一步是創(chuàng)建授權請求。該請求會設置用于標識您的應用的參數,并定義用戶將向您的應用授予的權限。

如果您使用 Google 客戶端庫進行 OAuth 2.0 身份驗證和授權,則需要創(chuàng)建并配置用于定義這些參數的對象。
如果您直接調用 Google OAuth 2.0 端點,系統(tǒng)會生成一個網址并針對該網址設置參數。
以下標簽定義了網絡服務器應用支持的授權參數。各種語言的示例還展示了如何使用客戶端庫或授權庫來配置可設置這些參數的對象。

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

將用戶重定向到 Google 的 OAuth 2.0 服務器,以啟動身份驗證和授權流程。這通常發(fā)生在您的應用首次需要訪問用戶數據時。對于增量授權,當您的應用首次需要訪問其尚未有權訪問的其他資源時,也會執(zhí)行此步驟。

Google 的 OAuth 2.0 服務器對用戶進行身份驗證,并在征得用戶同意后允許您的應用訪問所請求的范圍。系統(tǒng)會使用您指定的重定向網址將響應發(fā)送回您的應用。

第 3 步:Google 提示用戶同意

在此步驟中,用戶可以決定是否向應用請求訪問權限。在此階段,Google 會顯示一個意見征求窗口,其中會顯示應用的名稱以及使用用戶的授權憑據請求訪問權限的 Google API 服務以及要授予的訪問權限范圍的摘要。然后,用戶可以同意向您的應用所請求的一個或多個范圍授予訪問權限,或拒絕該請求。

在此階段,您的應用會等待 Google 的 OAuth 2.0 服務器響應(表明是否授予了任何訪問權限),因此在此階段無需執(zhí)行任何操作。下一步中說明了該響應。

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

OAuth 2.0 服務器使用請求中指定的網址響應您應用的訪問請求。

如果用戶批準了該訪問請求,響應中將包含授權代碼。如果用戶未批準該請求,則響應中會包含錯誤消息。返回網絡服務器的授權代碼或錯誤消息會顯示在查詢字符串上,如下所示:

第 5 步:使用授權代碼交換刷新令牌和訪問令牌

網絡服務器收到授權代碼后,可以使用授權代碼換取訪問令牌。

調用 Google API

重定向 URI 驗證規(guī)則

Google 會應用以下驗證規(guī)則來重定向 URI,以幫助開發(fā)者確保其應用安全無虞。您的重定向 URI 必須遵守這些規(guī)則。如需了解網域、主機、路徑、查詢、架構和用戶信息的定義,請參閱 RFC 3986 第 3 節(jié)。

增量授權

在 OAuth 2.0 協議中,您的應用會請求訪問由范圍標識的資源。這被認為是一種最佳的用戶體驗做法,即在您需要時對資源進行授權。為了啟用這種做法,Google 的授權服務器支持增量授權。此功能可讓您根據需要請求范圍,如果用戶為新范圍授予權限,則會返回授權代碼,該代碼可能會交換包含用戶向項目授予的所有范圍的令牌。

例如,如果應用支持用戶試聽曲目和創(chuàng)建合輯,在登錄時可能需要的資源可能很少,可能只有登錄用戶的名字。但是,保存已完成的合輯需要訪問其 Google 云端硬盤。多數人會在應用確實需要的時候訪問他們的 Google 云端硬盤,自然會發(fā)現應用很自然。

在這種情況下,在登錄時,應用可能會請求 openidprofile 范圍來執(zhí)行基本登錄,然后在第一次請求保存組合時請求 https://www.googleapis.com/auth/drive.file 范圍。

要實現增量授權,您需要完成請求訪問令牌的常規(guī)流程,但請確保授權請求包含之前授予的范圍。這種方法可讓您的應用不必管理多個訪問令牌。

以下規(guī)則適用于通過增量授權獲得的訪問令牌:

  • 此令牌可用于訪問與新合并的授權中任何一個范圍對應的資源。
  • 當您使用合并授權的刷新令牌獲取訪問令牌時,訪問令牌代表合并授權,可用于響應中包含的任何 scope 值。
  • 合并授權包含用戶向 API 項目授予的所有范圍,即使授權來自不同的客戶端也是如此。例如,如果用戶使用應用的桌面客戶端授予對一個范圍的訪問權限,然后通過移動客戶端向同一應用授予另一個范圍的訪問權限,則合并授權將同時包括這兩個范圍。
  • 如果您撤消代表合并授權的令牌,則代表關聯用戶同時撤消該授權范圍的所有訪問權限。

注意:如果選擇包含已獲授權的范圍,系統(tǒng)會自動將用戶之前授予的范圍添加到您的授權請求。如果您的應用當前未獲準請求在響應中返回的所有范圍,則系統(tǒng)可能會顯示警告或錯誤頁面。如需了解詳情,請參閱未經驗證的應用。

第 1 步:設置授權參數中特定于語言的代碼示例以及第 2 步:重定向至 Google 的 OAuth 2.0 服務器中的示例 HTTP/REST 重定向網址均使用增量授權。下面的代碼示例還顯示了您需要添加才能使用增量授權的代碼。

刷新訪問令牌(離線訪問)

訪問令牌會定期過期,并成為相關 API 請求的無效憑據。如果您請求離線訪問與此令牌相關聯的范圍,則可以刷新訪問令牌,而無需提示用戶授予權限(包括用戶不存在時)。

  • 如果您使用 Google API 客戶端庫,則客戶端對象會根據需要刷新訪問令牌,前提是您將該對象配置為可離線訪問。
  • 如果您未使用客戶端庫,則需要在將用戶重定向到 Google 的 OAuth 2.0 服務器時將 access_type HTTP 查詢參數設為 offline。在這種情況下,當您用授權代碼交換訪問令牌時,Google 的授權服務器會返回刷新令牌。然后,如果訪問令牌過期(或其他任何時間),您可以使用刷新令牌來獲取新的訪問令牌。

對于需要在用戶不存在時訪問 Google API 的任何應用,請求離線訪問是必需的。例如,如果應用在預定時間執(zhí)行備份服務或執(zhí)行操作,那么在用戶不存在時必須能夠刷新其訪問令牌。默認訪問方式稱為 online。

服務器端 Web 應用、已安裝的應用和設備均在授權過程中獲取刷新令牌。刷新令牌通常不用于客戶端 (JavaScript) Web 應用。

撤消令牌

在某些情況下,用戶可能會想撤消授予某個應用的訪問權限。用戶可以通過訪問帳號設置來撤消訪問權限。如需了解詳情,請參閱移除有權訪問您帳號的第三方網站和應用的網站或應用訪問權限部分。

應用也能夠以編程方式撤消其訪問權限。在用戶退訂、移除應用或應用所需的 API 資源發(fā)生了顯著變化的情況下,程序化撤消非常重要。換言之,移除流程的一部分可能包括 API 請求,以確保之前授予應用的權限被移除。

注意:成功撤消后,可能需要一些時間才能完全撤消。

完整示例

import json

import flask
import requests


app = flask.Flask(__name__)

CLIENT_ID = '123456789.apps.googleusercontent.com'
CLIENT_SECRET = 'abc123'  # Read from a file or environmental variable in a real app
SCOPE = 'https://www.googleapis.com/auth/drive.metadata.readonly'
REDIRECT_URI = 'http://example.com/oauth2callback'


@app.route('/')
def index():
  if 'credentials' not in flask.session:
    return flask.redirect(flask.url_for('oauth2callback'))
  credentials = json.loads(flask.session['credentials'])
  if credentials['expires_in'] <= 0:
    return flask.redirect(flask.url_for('oauth2callback'))
  else:
    headers = {'Authorization': 'Bearer {}'.format(credentials['access_token'])}
    req_uri = 'https://www.googleapis.com/drive/v2/files'
    r = requests.get(req_uri, headers=headers)
    return r.text


@app.route('/oauth2callback')
def oauth2callback():
  if 'code' not in flask.request.args:
    auth_uri = ('https://accounts.google.com/o/oauth2/v2/auth?response_type=code'
                '&client_id={}&redirect_uri={}&scope={}').format(CLIENT_ID, REDIRECT_URI, SCOPE)
    return flask.redirect(auth_uri)
  else:
    auth_code = flask.request.args.get('code')
    data = {'code': auth_code,
            'client_id': CLIENT_ID,
            'client_secret': CLIENT_SECRET,
            'redirect_uri': REDIRECT_URI,
            'grant_type': 'authorization_code'}
    r = requests.post('https://oauth2.googleapis.com/token', data=data)
    flask.session['credentials'] = r.text
    return flask.redirect(flask.url_for('index'))


if __name__ == '__main__':
  import uuid
  app.secret_key = str(uuid.uuid4())
  app.debug = False
  app.run()

問題: 為什么先請求授權碼,然后用授權碼獲取訪問令牌。 為什么不直接返回訪問令牌。

image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容