Google OAuth 2.0 系统支持服务器与服务器之间的互动,例如网络间的互动。 和 Google 服务。对于这种情况,您需要一个服务账号, 是属于您的应用程序而不是某个最终用户的账号。您的 应用会代表服务账号调用 Google API,这样用户就不必直接 。这种情况有时称为“两方模式的 OAuth”,或“2LO”。(相关字词 “三足式 OAuth”是指您的应用代表调用 Google API 的场景 最终用户的内容,有时需要征得用户同意。)
通常,当应用使用 Google API 工作时,会使用服务账号 自己的数据,而不是用户的数据。例如,使用 Google Cloud 的 用于数据持久化的数据存储区将使用服务账号来验证其对 Google Cloud Datastore API。
Google Workspace 网域管理员还可以 向服务账号授予全网域权限,以访问用户 代表域内用户共享的数据。
本文档介绍应用如何通过以下方式完成服务器到服务器 OAuth 2.0 流程: 使用 Google API 客户端库(推荐)或 HTTP。
概览
要支持服务器与服务器之间的交互,请先在以下位置为您的项目创建一个服务账号: API Console。如果您想访问以下国家/地区用户的用户数据: 您的 Google Workspace 账号,然后向该服务账号授予全网域访问权限。
然后,您的应用会准备使用服务账号的 向 OAuth 2.0 身份验证服务器请求访问令牌。
最后,您的应用可以使用访问令牌来调用 Google API。
创建服务账号
服务账号的凭据包含一个生成的电子邮件地址,该地址是唯一的,并且至少 一个公钥/私钥对。如果启用了全网域授权功能,那么客户端 ID 也会 服务账号的凭据
如果您的应用在 Google App Engine 上运行,系统将在 创建项目时所需的资源。
如果您的应用在 Google Compute Engine 上运行,则系统还会设置一个服务账号 但在创建项目时自动创建,但必须指定 应用需要的访问权限。有关 请参阅 准备实例以使用服务账号。
如果您的应用未在 Google App Engine 或 Google Compute Engine 上运行,您必须获取 Google API Console中的这些凭据。生成服务账号 凭据,或者要查看已生成的公共凭据,请执行以下操作:
首先,创建一个服务帐户:
- 打开 Service accounts page。
- If prompted, select a project, or create a new one.
- 单击 创建服务帐户。
- 在Service account details下,键入服务帐户的名称、ID 和描述,然后点击Create and continue 。
- 可选:在Grant this service account access to project下,选择要授予服务帐户的 IAM 角色。
- 单击继续。
- 可选:在Grant users access to this service account下,添加允许使用和管理服务帐户的用户或组。
- 单击完成。
接下来,创建一个服务帐户密钥:
- 单击您创建的服务帐户的电子邮件地址。
- 单击密钥选项卡。
- 在添加密钥下拉列表中,选择创建新密钥。
- 单击创建。
您的新公钥/私钥对已生成并下载到您的机器上;它作为私钥的唯一副本。您有责任安全地存储它。如果您丢失了这个密钥对,您将需要生成一个新的。
您可以返回到 API Console 随时查看该电子邮件地址,公开 密钥指纹和其他信息,或生成额外的公钥/私钥对。对于 请参阅 API Console,参见 API Console中的服务账号 帮助文件。
记下服务账号的电子邮件地址并存储服务账号的私钥 文件放在您的应用可访问的位置。您的应用需要它们 授权的 API 调用。
将全网域授权委派给服务账号
组织的 Workspace 管理员可以使用 Google Workspace 账号向 应用来代表 Google Workspace 网域中的用户访问 Workspace 用户数据。例如: 使用 Google 日历 API 将活动添加到 Google Workspace 网域将使用服务账号访问 。授权服务账号代表网域中的用户访问数据 有时也称为“全网域授权”服务账号
要将全网域授权委派给某个服务账号, Workspace 网域必须完成以下步骤:
- 来自您的 Google Workspace 网域的 管理控制台中,前往主菜单 安全 > 访问权限和数据控制 >API 控件。
- 在全网域授权窗格中,选择管理全网域授权。
- 点击新增。
- 在客户端 ID 字段中,输入服务账号的客户端 ID。您可以 您的服务账号的客户端 ID Service accounts page。
- 在 OAuth 范围(以英文逗号分隔)字段中,输入您的授权范围列表 应向其授予访问权限。例如,如果您的应用需要 拥有 Google Drive API 和 Google Calendar API 的完整访问权限,请输入: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar。
- 点击授权。
您的应用现在有权以 Workspace 网域中的用户的身份进行 API 调用( "模拟"用户)。在准备进行这些委托 API 调用时,您需要明确指定用户 模拟。
准备进行委托 API 调用
Java
在您从
API Console,请使用
适用于 Java 的 Google API 客户端库
利用服务账号的凭据创建 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("workspace-user@example.com");
上面的代码使用 GoogleCredential
对象来调用其 createDelegated()
方法。createDelegated()
方法的参数必须是属于
Workspace 账号。发出请求的代码将使用此凭据来调用 Google
API 访问 Cloud Storage 存储分区。
Python
在您从 API Console,请使用 适用于 Python 的 Google API 客户端库 以完成下列步骤:
- 根据服务账号的凭据和
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 上开发应用,可以使用 应用默认凭据 这样可以简化流程
- 委托全网域授权
如果您已向服务账号授予了全网域访问权限,并且希望 模拟用户账号,请使用现有用户账号的
with_subject
方法ServiceAccountCredentials
对象。例如:delegated_credentials = credentials.with_subject('user@example.org')
使用 Credentials 对象调用您应用中的 Google API。
HTTP/REST
在您从 API Console,您的应用需要完成 操作步骤:
- 创建一个 JSON Web 令牌(JWT,发音为“jot”),其中包括标头、声明集、 和签名。
- 从 Google OAuth 2.0 授权服务器请求访问令牌。
- 处理授权服务器返回的 JSON 响应。
以下部分介绍了如何完成这些步骤。
如果响应包含访问令牌,您可以使用访问令牌 调用 Google API。(如果响应不包含访问权限 令牌,则您的 JWT 和令牌请求格式不正确,或者服务账号可能 无权访问所请求的范围。)
当访问令牌到期时,您的应用将生成另一个 JWT、为其签名并请求另一个访问令牌。
![您的服务器应用使用 JWT 向 Google
授权服务器,然后使用该令牌调用 Google API 端点。否
最终用户的参与。](https://developers-dot-devsite-v2-prod.appspot.com/static/identity/protocols/oauth2/images/flows/jwt.png?authuser=7&hl=zh-cn)
本部分的其余内容将具体介绍如何创建 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 标头
标头包含三个字段,用于表示签名算法、 该断言和 [服务账号的密钥 ID] key](https://cloud.google.com/iam/docs/reference/rest/v1/projects.serviceAccounts.keys) 签名 JWT。算法和格式是必填项,每个字段只有 一个值。此标题会随着更多算法和格式的引入而发生变化 。密钥 ID 是可选的,如果指定的密钥 ID 不正确,GCP 将尝试 与服务账号关联的所有密钥,以验证令牌并拒绝令牌(如果 未找到有效密钥。Google 保留拒绝密钥 ID 不正确的令牌的权利 。
服务账号依赖于 RSA SHA-256 算法和 JWT 令牌格式。因此 标头的 JSON 表示法如下所示:
{"alg":"RS256","typ":"JWT", "kid":"370ab79b4513eb9bad7c9bd16a95cb76b5b2a56a"}
其 Base64url 表示形式如下所示:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsICJraWQiOiIzNzBhYjc5YjQ1MTNlYjliYWQ3YzliZDE2YTk1Y2I3NmI1YjJhNTZhIn0=
构建 JWT 声明集
JWT 声明集包含 JWT 的相关信息,包括 请求(范围)、令牌的目标、颁发者、令牌颁发的时间 以及令牌的生命周期大部分字段是必填字段。与 JWT 标头一样, JWT 声明集是一个 JSON 对象,用于计算签名。
必需的声明
JWT 声明集中的必需声明如下所示。它们可能会以任意顺序展示 声明集。
名称 | 说明 |
---|---|
iss |
服务账号的电子邮件地址。 |
scope |
应用请求的权限列表(用空格分隔)。 |
aud |
断言预期目标的描述符。创建访问令牌时
请求此值始终为 https://oauth2.googleapis.com/token 。 |
exp |
断言的到期时间,以自世界协调时间 (UTC) 00:00:00 以来的秒数表示。 1970 年 1 月 1 日。此值最多比发放时间晚 1 小时。 |
iat |
发出断言的时间,以自世界协调时间 (UTC) 00:00:00 以来的秒数表示。 1970 年 1 月 1 日。 |
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
字段的访问令牌请求将是
错误。
显示包含 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 网络签名 (JWS) 是一套规范,用于指导 JWT。签名的输入是以下内容的字节数组:
{Base64url encoded header}.{Base64url encoded claim set}
计算签名时,必须使用 JWT 标头中的签名算法。通过
只有 Google OAuth 2.0 授权服务器支持的签名算法是
SHA-256 哈希算法。它在 alg
中以 RS256
表示,
字段。
使用 SHA256withRSA(也称为 具有 SHA-256 哈希函数的 RSASSA-PKCS1-V1_5-SIGN)使用从 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
请求,正文为 网址
编码。网址如下所示:
https://oauth2.googleapis.com/token
HTTPS POST
请求中需要以下参数:
名称 | 说明 |
---|---|
grant_type |
使用以下字符串,并根据需要进行网址编码:
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
Java
使用 GoogleCredential
对象调用 Google API,方法是完成
操作步骤:
- 使用
GoogleCredential
对象。例如:SQLAdmin sqladmin = new SQLAdmin.Builder(httpTransport, JSON_FACTORY, credential).build();
- 使用
该服务对象提供的接口。
例如,要列出精彩示例-123 中的 Cloud SQL 数据库实例,
项目:
SQLAdmin.Instances.List instances = sqladmin.instances().list("exciting-example-123").execute();
Python
使用已获授权的 Credentials
对象调用 Google API,方法是完成
操作步骤:
- 为要调用的 API 构建服务对象。您构建了一个服务对象
方法是使用 API 的名称和版本以及 API 的
build
已授权的Credentials
对象。例如,要调用 Cloud SQL 管理 API:import googleapiclient.discovery sqladmin = googleapiclient.discovery.build('sqladmin', 'v1beta3', credentials=credentials)
- 使用
该服务对象提供的接口。
例如,要列出精彩示例-123 中的 Cloud SQL 数据库实例,
项目:
response = sqladmin.instances().list(project='exciting-example-123').execute()
HTTP/REST
在您的应用获得访问令牌后,您就可以使用该令牌调用 Google
API 代表指定的服务账号,或者
用户账号(如果已授予 API 所需的访问权限范围)。为此,请添加
通过添加 access_token
查询来获取对 API 的请求中的访问令牌
参数或 Authorization
HTTP 标头 Bearer
值。如有可能,
最好使用 HTTP 标头,因为查询字符串通常显示在服务器日志中。大多数
可以使用客户端库来设置对 Google API 的调用(例如,
调用 Drive Files API)。
您可以访问以下网址,试用所有 Google API 并查看其作用域: OAuth 2.0 Playground。
HTTP GET 示例
对
drive.files
端点(Drive Files API),同时使用 Authorization: Bearer
HTTP
可能如下所示。请注意,您需要指定自己的访问令牌:
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. |
如果您尝试使用全网域授权功能,则相应服务账号未在 用户网域的管理控制台 |
确保在
管理控制台中用户的全网域授权页面,
授权过程通常需要几分钟的时间,但最长可能需要 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 |
(任意值) | 如果您使用的是全网域授权功能,则请求的一个或多个范围未获得授权 管理控制台 |
确保在
管理控制台中用户的全网域授权页面,
授权过程通常需要几分钟的时间,但最长可能需要 24 小时才能生效。 您的 Google 账号中的所有用户都会看到这一消息。 |
admin_policy_enforced |
(任意值) | 由于 Google Workspace 管理员的政策。 |
参阅 Google Workspace 管理员帮助文章 控制哪些第三方和 内部应用会访问 Google Workspace 数据。 管理员可以限制对所有范围或敏感范围和受限范围的访问权限,直到 访问权限会明确授予您的 OAuth 客户端 ID。 |
invalid_client |
(任意值) |
OAuth 客户端或 JWT 令牌无效或配置错误。 如需了解详情,请参阅错误说明。 |
请确保 JWT 令牌有效且包含正确的声明。 检查 OAuth 客户端和服务账号是否 并且您使用的是正确的电子邮件地址。 检查 JWT 令牌是否正确,以及 请求。 |
invalid_grant |
Not a valid email. |
该用户不存在。 | 检查 sub 声明(字段)中的电子邮件地址是否正确。 |
invalid_grant |
|
这通常意味着本地系统时间不正确。如果
exp 值与 iat 值之间的间隔超过 65 分钟,
或 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 的 请注意, |
disabled_client |
The OAuth client was disabled. |
用于对 JWT 断言进行签名的密钥已停用。 |
转到 Google API Console,在 IAM &管理 >服务账号,请启用包含“密钥 ID”的服务账号已使用 对断言进行签名。 |
org_internal |
This client is restricted to users within its organization. |
请求中的 OAuth 客户端 ID 属于某个项目(限制对 Google 的访问) 特定 Google Cloud Organization(Google Cloud 组织)。 |
使用组织提供的服务账号进行身份验证。确认 用户类型 配置。 |
附录:不使用 OAuth 的服务账号授权
对于某些 Google API,您可以使用已签名的 JWT 直接作为 不记名令牌,而不是 OAuth 2.0 访问令牌。如果可以,您可以避免 在进行 API 调用之前,先向 Google 的授权服务器发出网络请求。
如果您要调用的 API 已在 Google API GitHub 代码库 您可以使用 JWT 而非访问令牌进行授权的 API 调用。为此,请执行以下操作:
- 按照上述说明创建服务账号。请务必 请保留您在创建账号时获得的 JSON 文件。
- 使用任何标准 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 文件。 - 对于
iss
和sub
字段,请指定您的服务账号的电子邮件地址 地址。您可以在服务的client_email
字段中找到此值 账号 JSON 文件。 - 对于
aud
字段,请指定 API 端点。例如:https://SERVICE.googleapis.com/
。 - 对于
iat
字段,指定当前 Unix 时间,exp
字段,指定正好 3600 秒之后,即 JWT 将 过期。
使用在服务账号 JSON 文件中找到的私钥通过 RSA-256 为 JWT 签名。
例如:
Java
使用 google-api-java-client 和 java-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')
- 使用已签名的 JWT 作为不记名令牌来调用 API:
GET /v1/projects/abc/databases/123/indexes HTTP/1.1 Authorization: Bearer SIGNED_JWT Host: firestore.googleapis.com
实施跨账号保护
您应采取的额外措施来保护用户的个账号实现了跨账号功能 利用 Google 的跨账号保护服务进行保护。通过这项服务 订阅安全事件通知,这些通知可向您的应用提供 关于用户账号的重大变化然后,您可以根据这些信息 您决定如何响应事件。
下面列举了一些示例来说明 Google 的跨账号保护服务发送到您应用的事件类型:
-
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked
-
https://schemas.openid.net/secevent/oauth/event-type/token-revoked
-
https://schemas.openid.net/secevent/risc/event-type/account-disabled
请参阅 使用“跨账号保护”页面保护用户账号 。