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

使用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 Workspace域管理員還可以授予服務帳戶整個域的權限,以代表該域中的用戶訪問用戶數據。

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

概述

要支持服務器到服務器的交互,請首先在API Console中為您的項目創建一個服務帳戶。如果要訪問Google Workspace帳戶中用戶的用戶數據,則將對服務帳戶的全域訪問權限委派給該用戶。

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

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

創建服務帳戶

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

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

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

如果您的應用程序不在Google App 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. 單擊 創建密鑰 ,然後單擊創建

您的新公鑰/私鑰對已生成並下載到您的計算機;它充當私鑰的唯一副本。您有責任安全地存儲它。如果丟失此密鑰對,則需要生成一個新的密鑰對。

如果您需要向服務帳戶授予G Suite域範圍內的權限 ,請單擊您創建的服務帳戶的電子郵件地址,然後從“ 唯一ID”框中復制該值。

要將權限委派給服務帳戶,請使用複制的值作為客戶端ID。

您可以隨時返回API Console ,以查看電子郵件地址,公鑰指紋和其他信息,或生成其他公/私鑰對。有關API Console中服務帳戶憑據的更多詳細信息,請參閱API Console幫助文件中的 服務帳戶

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

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

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

要將域範圍的權限委派給服務帳戶,請首先在Service accounts page中為現有服務帳戶啟用域範圍的委派,或者創建一個啟用了域範圍的委派的新服務帳戶

然後,Google Workspace域的超級管理員必須完成以下步驟:

  1. 在您的Google Workspace域的管理控制台中,轉到主菜單 >安全> API控件
  2. 在“域範圍委派”窗格中,選擇“管理域範圍委派”
  3. 單擊添加新的
  4. 客戶ID字段中,輸入服務帳戶的客戶ID 。您可以在Service accounts page中找到服務帳戶的客戶ID。
  5. OAuth範圍(以逗號分隔)字段中,輸入應授予您的應用程序訪問權限的範圍列表。例如,如果您的應用程序需要在域範圍內對Google Drive API和Google Calendar API的完全訪問權限,請輸入: https : //www.googleapis.com/auth/drive,https://www.googleapis.com/auth / calendar
  6. 點擊授權

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

準備進行授權的API調用

爪哇

從API Console獲得客戶端電子郵件地址和私鑰後,請使用Google APIs 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));

如果您要在Google Cloud Platform上開發應用程序,則可以改用應用程序默認憑據,這樣可以簡化流程。

委託域範圍的權限

如果您已授予服務帳戶在域範圍內的訪問權限,並且您想模擬一個用戶帳戶,請使用GoogleCredential對象的createDelegated方法指定該用戶帳戶的電子郵件地址。例如:

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

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

Python

從API Console獲取客戶端電子郵件地址和私鑰後,請使用適用於PythonGoogle API客戶端庫完成以下步驟:

  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)

    如果您要在Google Cloud Platform上開發應用程序,則可以改用應用程序默認憑據,這樣可以簡化流程。

  2. 委託域範圍的權限

    如果您已委派了對服務帳戶的域範圍訪問權限,並且要模擬用戶帳戶,請使用現有ServiceAccountCredentials對象的with_subject方法。例如:

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

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

HTTP / REST

從API Console獲取客戶端ID和私鑰後,您的應用程序需要完成以下步驟:

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

以下各節描述瞭如何完成這些步驟。

如果響應中包含訪問令牌,則可以使用該訪問令牌來調用Google API 。 (如果響應中不包含訪問令牌,則您的JWT和令牌請求可能格式不正確,或者服務帳戶可能無權訪問所請求的範圍。)

當訪問令牌到期時,您的應用程序將生成另一個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聲明的到期時間,指定為自1970年1月1日00:00:00 UTC以來的秒數。此值在發出時間之後最長為1小時。
iat發出聲明的時間,指定為自1970年1月1日UTC 00:00:00以來的秒數。

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的訪問

要獲得授予應用程序委派資源訪問權限的訪問令牌,請在JWT聲明集中將用戶的電子郵件地址作為sub字段的值。

名稱描述
sub應用程序正在請求委派訪問權限的用戶的電子郵件地址。

如果應用程序無權模擬用戶,則對包含sub字段的訪問令牌請求的響應將為error

包含sub字段的JWT聲明集的示例如下所示:

{
  "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-safe編碼。以下是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 Web簽名(JWS)是指導為JWT生成簽名的機制的規範。簽名的輸入是以下內容的字節數組:

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

計算簽名時,必須使用JWT標頭中的簽名算法。 Google OAuth 2.0授權服務器支持的唯一簽名算法是使用SHA-256哈希算法的RSA。這在JWT標頭的alg字段中表示為RS256

使用從Google API Console獲得的私鑰,使用SHA256withRSA(也稱為帶有SHA-256哈希函數的RSASSA-PKCS1-V1_5-SIGN)對輸入的UTF-8表示進行簽名。輸出將是一個字節數組。

然後,簽名必須是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編碼的。 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對象調用Google API:

  1. 為您要使用GoogleCredential對象調用的API創建服務對象。例如:
    SQLAdmin sqladmin =
        new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
  2. 使用服務對象提供接口向API服務發出請求。例如,要列出令人興奮的示例123項目中的Cloud SQL數據庫實例:
    SQLAdmin.Instances.List instances =
        sqladmin.instances().list("exciting-example-123").execute();

Python

完成以下步驟,使用授權的Credentials對象調用Google API:

  1. 為您要調用的API構建服務對象。您可以通過使用API​​的名稱和版本以及授權的Credentials對象調用build函數來構建服務對象。例如,要調用Cloud SQL管理API的版本1beta3:
    import googleapiclient.discovery
    
    sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
  2. 使用服務對象提供接口向API服務發出請求。例如,要列出令人興奮的示例123項目中的Cloud SQL數據庫實例:
    response = sqladmin.instances().list(project='exciting-example-123').execute()

HTTP / REST

您的應用程序獲取訪問令牌後,如果已授予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

訪問令牌何時過期

由Google OAuth 2.0授權服務器發出的訪問令牌將在expires_in值提供的持續時間之後過期。當訪問令牌過期時,應用程序應生成另一個JWT,對其進行簽名,然後請求另一個訪問令牌。

JWT錯誤代碼

error字段error_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的系統上的時鍾正確。如有必要,將您的時間與Google NTP同步。

invalid_grant Invalid JWT Signature.

JWT斷言使用不與客戶端電子郵件標識的服務帳戶關聯的私鑰簽名。

或者,JWT斷言可能被錯誤地編碼-它必須是Base64編碼的,沒有換行符或填充等號。

解碼JWT聲明集,並驗證對聲明進行簽名的密鑰與服務帳戶相關聯。

嘗試使用Google提供的OAuth庫,以確保正確生成JWT。

invalid_scope Invalid OAuth scope or ID token audience provided.未請求任何範圍(範圍的空列表),或者所請求的範圍之一不存在(即無效)。

確保已填充JWT的scope聲明(字段),並將其包含的範圍與要使用的API的已記錄範圍進行比較,以確保沒有錯誤或拼寫錯誤。

請注意,範圍聲明中的scope列表需要用空格而不是逗號分隔。

disabled_client The OAuth client was disabled.用於簽名JWT斷言的密鑰已禁用。

轉到Google API Console,然後在IAM&Admin> Service Accounts下,啟用包含用於簽署斷言的“密鑰ID”的服務帳戶。

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

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

如果要調用的API在Google API GitHub存儲庫中發布了服務定義,則可以使用JWT而不是訪問令牌進行授權的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。您可以在服務帳戶JSON文件的private_key_id字段中找到此值。
    • isssub字段中,指定服務帳戶的電子郵件地址。您可以在服務帳戶JSON文件的client_email字段中找到此值。
    • aud字段中,指定API端點。例如: https:// SERVICE .googleapis.com/
    • 對於iat字段,請指定當前的Unix時間,對於exp字段,請指定JWT到期的確切3600秒後的時間。

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

例如:

爪哇

使用google-api-java-clientjava-jwt

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. 使用簽名的JWT作為承載令牌來調用API:
    GET /v1/projects/abc/databases/123/indexes HTTP/1.1
    Authorization: Bearer SIGNED_JWT
    Host: firestore.googleapis.com