账号使用行业标准 OAuth 2.0 隐式 和 授权代码 流程进行关联。
您的服务必须支持符合 OAuth 2.0 标准的 授权 和 令牌交换 端点。在隐式流程中,Google 会在用户的浏览器中打开您的授权端点。成功登录后,您将向 Google 返回一个长期访问令牌。现在,此访问令牌会包含在 Google 发送的每个请求中。
在授权代码流程中,您需要两个端点:
授权端点,用于向尚未登录的用户显示登录界面。授权端点还会创建一个短期授权代码,以记录用户对所请求访问权限的同意情况。
令牌交换端点,负责两种类型的交换:
- 使用授权代码换取长期有效的刷新令牌和短期有效的访问令牌。当用户完成账号关联流程时,就会发生此交换。
- 将长期有效的刷新令牌换成短期有效的访问令牌。当 Google 需要新的访问令牌(因为现有访问令牌已过期)时,就会发生这种交换。
选择 OAuth 2.0 流程
虽然隐式流程更易于实现,但 Google 建议通过隐式流程签发的访问令牌永不过期。这是因为,在隐式流程中,令牌过期后,系统会强制用户重新关联其账号。如果您出于安全考虑需要令牌过期,我们强烈建议您改用授权码流程。
设计准则
本部分介绍了您为 OAuth 关联流程托管的用户屏幕的设计要求和建议。在 Google 应用调用该 API 后,您的平台会向用户显示登录 Google 页面和账号关联意见征求界面。同意关联账号后,系统会将用户重定向回 Google 的应用。
要求
- 您必须说明用户的账号将与 Google 相关联,而非 Google Home 或 Google 助理等特定 Google 产品相关联。
建议
建议您执行以下操作:
显示 Google 的隐私权政策。在同意屏幕上添加指向 Google 隐私权政策的链接。
要共享的数据。使用清晰简洁的语言告知用户 Google 需要哪些用户数据以及原因。
添加醒目的号召性用语。在用户同意页面上提供明确的号召性用语,例如“同意并关联”。这是因为用户需要了解他们需要与 Google 分享哪些数据才能关联账号。
可以取消。为用户提供返回或取消链接的途径,如果用户选择不进行关联。
明确的登录流程。确保用户有明确的 Google 账号登录方法,例如用户名和密码字段或使用 Google 账号登录。
能够解除关联。提供一种可让用户解除关联的机制,例如指向您平台上账号设置的网址。或者,您也可以添加指向 Google 账号的链接,以便用户管理其关联的账号。
能够更改用户账号。建议用户切换账号的方法。如果用户通常拥有多个账号,这种做法尤为有益。
- 如果用户必须关闭意见征求界面才能切换账号,请向 Google 发送可恢复的错误,以便用户可以使用 OAuth 关联和隐式流程登录所需的账号。
添加您的徽标。在意见征求页面上显示您的公司徽标。 按照您的样式准则放置徽标。如果您还想显示 Google 的徽标,请参阅徽标和商标。
创建项目
如需创建项目以使用账号关联,请执行以下操作:
- 前往 Google API 控制台。
- 点击 Create project 。
- 输入名称或接受生成的建议。
- 确认或修改任何剩余字段。
- 点击创建 。
如需查看项目 ID,请执行以下操作:
- 前往 Google API 控制台。
- 在着陆页的表格中找到您的项目。项目 ID 会显示在 ID 列中。
配置 OAuth 权限请求页面
Google 账号关联过程包含一个权限请求页面,该页面会告知用户请求访问其数据的应用、应用请求的数据类型以及适用的条款。您需要先配置 OAuth 权限请求页面,然后才能生成 Google API 客户端 ID。
- 打开 Google API 控制台的 OAuth 权限请求页面 页面。
- 如果系统提示您选择项目,请选择您刚刚创建的项目。
在“OAuth 权限请求页面”上,填写表单,然后点击“保存”按钮。
应用名称 :向用户征求同意的应用的名称。该名称应准确反映您的应用,并且与用户在其他位置看到的应用名称保持一致。应用名称将显示在账号关联权限请求页面上。
应用徽标:权限请求页面上显示的一张图片,用以让用户认出您的应用。徽标会显示在账号关联权限请求页面和账号设置中
支持邮箱 :用户用于针对其同意问题与您联系的邮箱。
Google API 的范围 :范围允许您的应用访问用户的私有 Google 数据。对于 Google 账号关联用例,默认范围(邮箱、个人资料、openid)就足够了,您无需添加任何敏感范围。通常,最佳做法是在需要访问权限时逐步请求范围,而不是提前请求。了解详情。
已获授权的网域 :为了保护您和您的用户,Google 只允许使用 OAuth 进行身份验证的应用使用已获授权的网域。您应用的链接必须托管在已获授权的网域上。了解详情。
应用首页链接 :应用的首页。必须托管在已获授权的网域上。
应用隐私权政策链接 :显示在 Google 账号关联权限请求页面上。必须托管在已获授权的网域上。
应用服务条款链接(可选) :必须托管在已获授权的网域上。
图 1. 虚构应用 Tunery 的 Google 账号关联权限请求页面
查看“验证状态”,如果您的应用需要验证,请点击“提交以进行验证”按钮,提交应用以进行验证。如需了解详情,请参阅 OAuth 验证要求。
实现 OAuth 服务器
授权代码流程的 OAuth 2.0 服务器实现包含两个端点,您的服务通过 HTTPS 提供这两个端点。第一个端点是授权端点,负责查找或征得用户同意以获取数据访问权限。授权端点会向尚未登录的用户显示登录界面,并记录用户对所请求访问权限的同意情况。第二个端点是令牌交换端点,用于获取加密字符串(称为令牌),这些令牌可授权用户访问您的服务。
当 Google 应用需要调用您某项服务的 API 时,Google 会同时使用这些端点来征得用户同意,以便代表用户调用这些 API。
Google 账号关联:OAuth 授权代码流程
以下序列图详细说明了用户、Google 和您服务的端点之间的互动。
角色和职责
下表定义了 Google 账号关联 (GAL) OAuth 流中各个参与者的角色和职责。请注意,在 GAL 中,Google 充当 OAuth 客户端,而您的服务充当身份/服务提供方。
| 执行者 / 组件 | GAL 角色 | 职责 |
|---|---|---|
| Google 应用 / 服务器 | OAuth 客户端 | 启动流程,接收授权代码,将其换成令牌,并安全地存储这些令牌以访问服务的 API。 |
| 您的授权端点 | 授权服务器 | 对用户进行身份验证,并征得用户同意,允许其与 Google 分享对自身数据的访问权限。 |
| 您的令牌交换端点 | 授权服务器 | 验证授权代码和刷新令牌,并向 Google 服务器发放访问令牌。 |
| Google 重定向 URI | 回调端点 | 从您的授权服务接收包含 code 和 state 值的用户重定向。 |
由 Google 发起的 OAuth 2.0 授权代码流程会话具有以下流程:
- Google 会在用户的浏览器中打开您的授权端点。如果流程是在仅支持语音的设备上针对某项操作启动的,Google 会将执行转移到手机。
- 用户登录(如果尚未登录),并授予 Google 权限以通过您的 API 访问其数据(如果尚未授予权限)。
- 您的服务创建授权代码并将其返回给 Google。为此,请将用户的浏览器重定向回 Google,并在请求中附上授权代码。
- Google 会将授权代码发送到您的令牌交换端点,该端点会验证代码的真实性,并返回访问令牌和刷新令牌。访问令牌是一种短期有效的令牌,您的服务会将其作为凭据来接受,以便访问 API。刷新令牌是一种长期有效的令牌,Google 可以存储并使用它在访问令牌过期时获取新的访问令牌。
- 用户完成账号关联流程后,Google 发送的每个后续请求都包含一个访问令牌。
处理授权请求
当您需要使用 OAuth 2.0 授权码流程执行账号关联时,Google 会将用户发送到您的授权端点,并发送包含以下参数的请求:
| 授权端点参数 | |
|---|---|
client_id |
您分配给 Google 的客户端 ID。 |
redirect_uri |
您将对此请求的响应发送到的网址。 |
state |
一种簿记值,在重定向 URI 中原封不动地传递回 Google。 |
scope |
可选:一组以空格分隔的范围字符串,用于指定 Google 请求授权的数据。 |
response_type |
要在响应中返回的值的类型。对于 OAuth 2.0 授权代码流程,响应类型始终为 code。 |
user_locale |
采用 RFC5646 格式的 Google 账号语言设置,用于以用户的首选语言本地化您的内容。 |
例如,如果您的授权端点位于 https://myservice.example.com/auth,则请求可能如下所示:
GET https://myservice.example.com/auth?client_id=GOOGLE_CLIENT_ID&redirect_uri=REDIRECT_URI&state=STATE_STRING&scope=REQUESTED_SCOPES&response_type=code&user_locale=LOCALE
如需让授权端点处理登录请求,请执行以下步骤:
- 验证
client_id是否与您分配给 Google 的客户端 ID 一致,以及redirect_uri是否与 Google 为您的服务提供的重定向网址一致。这些检查对于防止向意外或配置错误的客户端应用授予访问权限非常重要。如果您支持多个 OAuth 2.0 流程,还需确认response_type是否为code。 - 检查用户是否已登录您的服务。如果用户未登录,请完成服务的登录或注册流程。
- 生成一个授权代码,供 Google 用于访问您的 API。 授权代码可以是任何字符串值,但必须唯一表示用户、令牌所针对的客户端和代码的过期时间,并且不得可猜测。您通常会签发大约 10 分钟后过期的授权码。
- 确认
redirect_uri参数指定的网址具有以下格式:https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID https://oauth-redirect-sandbox.googleusercontent.com/r/YOUR_PROJECT_ID
- 将用户的浏览器重定向到
redirect_uri参数指定的网址。通过附加code和state参数进行重定向时,请添加您刚刚生成的授权代码和原始的未修改状态值。以下是生成的网址示例:https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID?code=AUTHORIZATION_CODE&state=STATE_STRING
处理令牌交换请求
您服务的令牌交换端点负责处理两种类型的令牌交换:
- 将授权代码交换为访问令牌和刷新令牌
- 将刷新令牌换成访问令牌
令牌交换请求包含以下参数:
| 令牌交换端点参数 | |
|---|---|
client_id |
此字符串用于将请求源标识为 Google。此字符串必须在您的系统中注册为 Google 的唯一标识符。 |
client_secret |
您向 Google 注册的用于服务的密钥字符串。 |
grant_type |
要兑换的令牌的类型。值为 authorization_code 或 refresh_token。 |
code |
如果值为 grant_type=authorization_code,则此参数是 Google 从您的登录或令牌交换端点收到的代码。 |
redirect_uri |
如果值为 grant_type=authorization_code,则此参数是初始授权请求中使用的网址。 |
refresh_token |
如果值为 grant_type=refresh_token,则此参数是 Google 从您的令牌交换端点收到的刷新令牌。 |
将授权代码交换为访问令牌和刷新令牌
用户登录后,您的授权端点会向 Google 返回一个时效很短的授权代码,然后 Google 会向您的令牌交换端点发送请求,以将该授权代码换成访问令牌和刷新令牌。
对于这些请求,grant_type 的值为 authorization_code,code 的值为您之前授予 Google 的授权代码的值。以下是使用授权代码交换访问令牌和刷新令牌的请求示例:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=authorization_code&code=AUTHORIZATION_CODE&redirect_uri=REDIRECT_URI
如需使用授权代码换取访问令牌和刷新令牌,令牌交换端点会通过执行以下步骤来响应 POST 请求:
- 验证
client_id是否将请求来源标识为授权来源,以及client_secret是否与预期值匹配。 - 验证授权代码是否有效且未过期,以及请求中指定的客户端 ID 是否与授权代码关联的客户端 ID 相符。
- 确认
redirect_uri参数指定的网址与初始授权请求中使用的值完全相同。 - 如果您无法验证上述所有条件,请返回 HTTP 400 Bad Request 错误,并将
{"error": "invalid_grant"}作为正文。 - 否则,使用授权代码中的用户 ID 生成刷新令牌和访问令牌。这些令牌可以是任何字符串值,但必须唯一表示用户和令牌所针对的客户端,并且不得可猜测。对于访问令牌,还要记录令牌的过期时间,该时间通常是在您发放令牌后一小时。刷新令牌不会过期。
- 在 HTTPS 响应的正文中返回以下 JSON 对象:
{ "token_type": "Bearer", "access_token": "ACCESS_TOKEN", "refresh_token": "REFRESH_TOKEN", "expires_in": SECONDS_TO_EXPIRATION }
Google 会存储用户的访问令牌和刷新令牌,并记录访问令牌的过期时间。当访问令牌过期时,Google 会使用刷新令牌从您的令牌交换端点获取新的访问令牌。
将刷新令牌换成访问令牌
当访问令牌过期时,Google 会向您的令牌交换端点发送请求,以将刷新令牌换成新的访问令牌。
对于这些请求,grant_type 的值为 refresh_token,而 refresh_token 的值为您之前授予 Google 的刷新令牌的值。以下是将刷新令牌换成访问令牌的请求示例:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
如需将刷新令牌换成访问令牌,令牌交换端点会通过执行以下步骤来响应 POST 请求:
- 验证
client_id是否将请求源标识为 Google,以及client_secret是否与预期值一致。 - 验证刷新令牌是否有效,以及请求中指定的客户端 ID 是否与刷新令牌关联的客户端 ID 相符。
- 如果您无法验证上述所有条件,请返回 HTTP 400 Bad Request 错误,并将
{"error": "invalid_grant"}作为正文。 - 否则,请使用刷新令牌中的用户 ID 生成访问令牌。这些令牌可以是任何字符串值,但必须唯一表示用户和令牌所针对的客户端,并且不得可猜测。对于访问令牌,还要记录令牌的过期时间,通常是在您发放令牌后一小时。
- 在 HTTPS 响应的正文中返回以下 JSON 对象:
{ "token_type": "Bearer", "access_token": "ACCESS_TOKEN", "expires_in": SECONDS_TO_EXPIRATION }
Handle userinfo requests
The userinfo endpoint is an OAuth 2.0 protected resource that return claims about the linked user. Implementing and hosting the userinfo endpoint is optional, except for the following use cases:
- Linked Account Sign-In with Google One Tap.
- Frictionless subscription on AndroidTV.
After the access token has been successfully retrieved from your token endpoint, Google sends a request to your userinfo endpoint to retrieve basic profile information about the linked user.
| userinfo endpoint request headers | |
|---|---|
Authorization header |
The access token of type Bearer. |
For example, if your userinfo endpoint is available at
https://myservice.example.com/userinfo, a request might look like the following:
GET /userinfo HTTP/1.1 Host: myservice.example.com Authorization: Bearer ACCESS_TOKEN
For your userinfo endpoint to handle requests, do the following steps:
- Extract access token from the Authorization header and return information for the user associated with the access token.
- If the access token is invalid, return an HTTP 401 Unauthorized error with using the
WWW-AuthenticateResponse Header. Below is an example of a userinfo error response: If a 401 Unauthorized, or any other unsuccessful error response is returned during the linking process, the error will be non-recoverable, the retrieved token will be discarded and the user will have to initiate the linking process again.HTTP/1.1 401 Unauthorized WWW-Authenticate: error="invalid_token", error_description="The Access Token expired"
If the access token is valid, return and HTTP 200 response with the following JSON object in the body of the HTTPS response:
If your userinfo endpoint returns an HTTP 200 success response, the retrieved token and claims are registered against the user's Google account.{ "sub": "USER_UUID", "email": "EMAIL_ADDRESS", "given_name": "FIRST_NAME", "family_name": "LAST_NAME", "name": "FULL_NAME", "picture": "PROFILE_PICTURE", }userinfo endpoint response subA unique ID that identifies the user in your system. emailEmail address of the user. given_nameOptional: First name of the user. family_nameOptional: Last name of the user. nameOptional: Full name of the user. pictureOptional: Profile picture of the user.
验证您的实现
您可以使用 OAuth 2.0 Playground 工具验证您的实现。
在该工具中,执行以下步骤:
- 点击配置 以打开“OAuth 2.0 配置”窗口。
- 在 OAuth flow(OAuth 流程)字段中,选择 Client-side(客户端)。
- 在 OAuth Endpoints 字段中,选择 Custom。
- 在相应字段中指定您的 OAuth 2.0 端点以及您分配给 Google 的客户端 ID。
- 在第 1 步部分中,请勿选择任何 Google 范围。请将此字段留空,或输入适用于您服务器的范围(如果您不使用 OAuth 范围,则输入任意字符串)。完成后,点击 Authorize APIs。
- 在第 2 步和第 3 步部分中,完成 OAuth 2.0 流程,并验证每个步骤是否按预期运行。
您可以使用 Google 账号关联演示工具验证您的实现。
在该工具中,执行以下步骤:
- 点击使用 Google 账号登录按钮。
- 选择您要关联的账号。
- 输入服务 ID。
- (可选)输入您将请求访问的一个或多个范围。
- 点击开始演示。
- 当系统提示时,请确认您可以同意或拒绝关联请求。
- 确认您已重定向到相应平台。