Google 致力於促進黑人社區的種族平等。 怎麼看。

將 OAuth 2.0 用於服務器到服務器應用程序

Google OAuth 2.0 系統支持服務器到服務器的交互,例如 Web 應用程序和 Google 服務之間的交互。對於這種情況,你需要一個服務帳戶,這是屬於你的應用程序,而不是對單個最終用戶的賬戶。您的應用程序代表服務帳號調用 Google API,因此用戶不會直接參與其中。這種情況有時稱為“兩條腿的 OAuth”或“2LO”。 (相關術語“三足 OAuth”是指您的應用程序代表最終用戶調用 Google API 並且有時需要用戶同意的場景。)

通常,當應用程序使用 Google API 處理自己的數據而不是用戶的數據時,應用程序會使用服務帳戶。例如,使用 Google Cloud Datastore 進行數據持久化的應用程序將使用服務帳戶來驗證其對 Google Cloud Datastore API 的調用。

谷歌工作區域管理員還可以授予服務帳戶域範圍內的授權訪問用戶數據代表域中的用戶的。

本文檔描述了應用程序如何使用 Google API 客戶端庫(推薦)或 HTTP 完成服務器到服務器 OAuth 2.0 流程。

概述

支持服務器到服務器交互,首先要建立在你的項目中的服務帳戶 API Console。如果您想訪問 Google Workspace 帳戶中用戶的用戶數據,請將域範圍的訪問權限委託給服務帳戶。

然後,您的應用程序準備進行授權 API 調用,方法是使用服務帳戶的憑據從 OAuth 2.0 身份驗證服務器請求訪問令牌。

最後,您的應用程序可以使用訪問令牌來調用 Google API。

創建服務帳號

服務帳戶的憑據包括生成的唯一電子郵件地址和至少一個公鑰/私鑰對。如果啟用了域範圍委派,則客戶端 ID 也是服務帳戶憑據的一部分。

如果您的應用程序在 Google App Engine 上運行,則在您創建項目時會自動設置一個服務帳戶。

如果您的應用程序在 Google Compute Engine 上運行,則在您創建項目時也會自動設置一個服務帳戶,但您必須在創建 Google Compute Engine 實例時指定您的應用程序需要訪問的範圍。欲了解更多信息,請參閱準備一個實例來使用服務帳戶

如果您的應用程序無法在谷歌應用程序引擎或谷歌計算引擎運行,必須獲得在這些憑據 Google API Console。要生成服務帳戶憑據,或查看您已生成的公共憑據,請執行以下操作:

首先,創建一個服務帳戶:

  1. 打開 Service accounts page
  2. If prompted, select a project, or create a new one.
  3. 點擊創建服務帳戶
  4. 服務帳戶的詳細信息,鍵入一個名稱,ID和服務帳戶的描述,然後單擊創建並繼續
  5. 可選:在授予此服務帳戶訪問到項目中,選擇IAM角色授予服務帳戶。
  6. 點擊繼續
  7. 可選:在授予用戶訪問該服務帳戶,添加允許使用和管理服務帳戶的用戶或組。
  8. 點擊完成
  9. 點擊創建鍵,然後單擊創建

接下來,創建一個服務帳戶密鑰:

  1. 單擊您創建的服務帳戶的電子郵件地址。
  2. 單擊Keys選項卡。
  3. 添加鍵下拉列表中,選擇創建新的密鑰
  4. 點擊創建

您的新公鑰/私鑰對已生成並下載到您的機器上;它是私鑰的唯一副本。您有責任安全地存儲它。如果您丟失了這個密鑰對,您將需要生成一個新的。

您可以返回到 API Console隨時查看電子郵件地址,公鑰指紋等信息,或產生額外的公共/私有密鑰對。有關服務帳戶憑據的詳細信息 API Console,請參閱服務帳戶在 API Console幫助文件。

記下服務帳戶的電子郵件地址,並將服務帳戶的私鑰文件存儲在您的應用程序可訪問的位置。您的應用程序需要它們來進行授權的 API 調用。

將域範圍的權限委派給服務帳戶

如果您有 Google Workspace 帳戶,則組織的管理員可以授權應用程序代表 Google Workspace 域中的用戶訪問用戶數據。例如,使用 Google Calendar API 向 Google Workspace 域中所有用戶的日曆添加事件的應用程序將使用服務帳戶代表用戶訪問 Google Calendar API。授權服務帳戶代表域中的用戶訪問數據有時稱為“將域範圍的權限委託給服務帳戶”。

要將域範圍的權限委派給服務帳號,Google Workspace 域的超級管理員必須完成以下步驟:

  1. 從您的工作空間谷歌域的管理控制台,進入主菜單 >安全> API控制
  2. 域寬代表團窗格中,選擇管理域範圍的代表團
  3. 點擊添加新的
  4. 客戶ID字段中輸入服務帳戶的客戶端ID。您可以找到您的服務帳戶的客戶ID Service accounts page
  5. OAuth範圍(以逗號分隔)字段中輸入範圍的列表中,你的應用程序應該被授予訪問權限。例如,如果你的應用需要域範圍內的完全訪問谷歌雲端硬盤API和谷歌日曆API,請輸入:https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth /日曆
  6. 點擊授權

您的應用程序現在有權以您域中的用戶身份進行 API 調用(以“模擬”用戶)。當您準備進行授權的 API 調用時,您可以指定要模擬的用戶。

準備進行授權的 API 調用

爪哇

當您獲得來自客戶的電子郵件地址和私有密鑰 API Console,使用谷歌API客戶端庫為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));

如果您正在開發在谷歌雲平台的應用程序,你可以使用應用程序的默認憑證代替,這樣可以簡化過程。

委派全域權限

如果你已經委派域範圍內的訪問服務帳戶,你要模擬用戶帳戶,指定與用戶帳戶的電子郵件地址createDelegated的方法GoogleCredential對象。例如:

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

使用GoogleCredential對象調用API的谷歌應用程序中。

Python

你獲得來自客戶的電子郵件地址和私鑰後 API Console,使用谷歌API客戶端庫的Python完成以下步驟:

  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)

    如果您正在開發在谷歌雲平台的應用程序,你可以使用應用程序的默認憑證代替,這樣可以簡化過程。

  2. 委派全域權限

    如果你已經委派域範圍內的訪問服務帳戶,你要模擬用戶帳戶,使用with_subject現有的方法ServiceAccountCredentials對象。例如:

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

使用 Credentials 對像在您的應用程序中調用 Google API。

HTTP/REST

你獲得來自客戶端ID和私鑰後 API Console,你的應用程序需要完成以下步驟:

  1. 創建一個 JSON Web 令牌(JWT,發音為“jot”),其中包括標頭、聲明集和簽名。
  2. 從 Google OAuth 2.0 授權服務器請求訪問令牌。
  3. 處理授權服務器返回的 JSON 響應。

以下部分描述瞭如何完成這些步驟。

如果響應包括訪問令牌,你可以使用令牌來訪問調用API谷歌。 (如果響應不包含訪問令牌,則您的 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斷言的到期時間,指定為自 UTC 時間 1970 年 1 月 1 日 00:00:00 以來的秒數。該值在發佈時間後最長為 1 小時。
iat發出斷言的時間,指定為自 1970 年 1 月 1 日 00:00:00 UTC 以來的秒數。

JWT 聲明集中所需字段的 JSON 表示如下所示:

{
  "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訪問權限

為了獲得令牌授權應用程序授權訪問資源的訪問,包括智威湯遜聲明組作為價值的用戶的電子郵件地址, 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 安全編碼。以下是 JWT 聲明集的 JSON 表示示例:

{
  "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)是規範,產生了智威湯遜簽名的引導機制。簽名的輸入是以下內容的字節數組:

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

計算簽名時必須使用 JWT 頭中的簽名算法。 Google OAuth 2.0 授權服務器支持的唯一簽名算法是使用 SHA-256 散列算法的 RSA。這表現為RS256alg在JWT報頭字段。

拍使用SHA256withRSA與從所獲得的私鑰的輸入(也稱為RSASSA-PKCS1-v1_5中-SIGN與SHA-256散列函數)的UTF-8表示 Google API Console。輸出將是一個字節數組。

然後簽名必須是 Base64url 編碼的。頭,如權利要求集,和簽名用句點(連接到一起. )字符。結果是 JWT。它應該如下(為清楚起見添加了換行符):

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

下面是 Base64url 編碼之前的 JWT 示例:

{"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編碼。網址如下所示:

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 API

爪哇

使用GoogleCredential對象通過完成以下步驟來調用谷歌的API:

  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對象通過完成以下步驟來調用谷歌的API:

  1. 為要調用的 API 構建服務對象。您可以通過調用建立AA服務對象build的名稱和版本的API和授權功能Credentials對象。例如,要調用的Cloud SQL管理API的版本1beta3:
    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

在您的應用程序獲得訪問令牌後,如果已授予 API 所需的訪問範圍,您可以使用該令牌代表給定的服務帳戶或用戶帳戶調用 Google API。要做到這一點,包括通過包括一個在請求令牌給API訪問access_token查詢參數或Authorization HTTP標頭Bearer值。如果可能,最好使用 HTTP 標頭,因為查詢字符串往往在服務器日誌中可見。在大多數情況下,你可以使用客戶端庫建立到谷歌的API您的來電(例如,當調用驅動器文件API )。

你可以嘗試所有的谷歌API和查看他們的範圍在的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

訪問令牌何時到期

訪問令牌由谷歌的OAuth 2.0授權服務器頒發的規定期限到期後expires_in值。當訪問令牌過期時,應用程序應生成另一個 JWT,對其進行簽名,並請求另一個訪問令牌。

JWT 錯誤代碼

errorerror_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.使用客戶端電子郵件地址而非管理控制台中的客戶端 ID(數字)對服務帳號進行了授權。域範圍內的代表團在管理控制台頁面,刪除客戶端,並與數字ID重新添加它。
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 的系統上的時鍾正確。如果有必要,同步你的時間谷歌NTP

invalid_grant Invalid JWT Signature.

JWT 斷言使用與客戶端電子郵件標識的服務帳戶無關的私鑰進行簽名,或者使用的密鑰已被刪除、禁用或已過期。

或者,JWT 斷言可能編碼不正確 - 它必須是 Base64 編碼的,沒有換行符或填充等號。

解碼 JWT 聲明集並驗證簽署斷言的密鑰與服務帳戶相關聯。

嘗試使用 Google 提供的 OAuth 庫來確保正確生成 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 ConsoleIAM與管理>服務帳戶下,使其中包含用於簽署斷言“鑰匙ID”的服務帳戶。

附錄:無需 OAuth 的服務帳戶授權

借助某些 Google API,您可以使用已簽名的 JWT 直接作為不記名令牌(而不是 OAuth 2.0 訪問令牌)進行授權 API 調用。如果可能,您可以避免在進行 API 調用之前向 Google 的授權服務器發出網絡請求。

如果你想調用API具有公佈在服務定義谷歌的API庫GitHub的,你可以使用一個智威湯遜,而不是一個訪問令牌做出授權API調用。這樣做:

  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在頭字段中,指定服務帳戶的私有密鑰ID。你可以找到在這個值private_key_id您的服務帳戶JSON文件的領域。
    • 對於isssub域,指定服務帳戶的電子郵件地址。你可以找到在這個值client_email您的服務帳戶JSON文件的領域。
    • 對於aud字段中指定的API端點。例如: https:// SERVICE .googleapis.com/
    • 對於iat字段中,指定當前Unix的時間,而對於exp字段,正是3600秒後,指定時間時,智威湯遜將到期。

使用在您的服務帳戶 JSON 文件中找到的私鑰,通過 RSA-256 對 JWT 進行簽名。

例如:

爪哇

使用谷歌的API的Java客戶端Java的智威湯遜

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作為承載令牌:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com