已关联的帐号登录

通过 Google 帐号关联,Google 帐号持有人可以快速、无缝、安全地连接到您的服务并与 Google 共享数据。

“关联的帐号登录”功能可让已将 Google 帐号关联到您的服务的用户启用一键登录 Google。这可以改善用户的体验,因为他们只需点击一下即可登录,而无需重新输入用户名和密码。这也减少了用户使用您的服务创建重复帐号的机会。

要求

如需实现关联的帐号登录,您必须满足以下要求:

  • 您的 Google 帐号 OAuth 关联实现支持 OAuth 2.0 授权代码流程。您的 OAuth 实现必须包含以下端点:
    • 授权端点来处理授权请求。
    • token endpoint 处理访问令牌和刷新令牌的请求。
    • userinfo 端点,以检索在关联的帐号登录过程中向用户显示的已关联用户的基本帐号信息。
  • 您拥有 Android 应用。

工作原理

前提条件 :用户之前已将他们的 Google 帐号与您的服务帐号相关联。

  1. 您可以在一键登录流程中选择显示关联的帐号。
  2. 用户会看到“一键登录”提示,以及使用关联的帐号登录服务的选项。
  3. 如果用户选择继续使用关联的帐号,Google 会向您的令牌端点发送请求,以保存授权代码。该请求包含您的服务颁发的用户访问令牌和 Google 授权代码。
  4. 您可以使用 Google 授权代码换取包含用户 Google 帐号相关信息的 Google ID 令牌。
  5. 在流程完成后,您的应用还会收到 ID 令牌,您可以将此 ID 与服务器收到的 ID 令牌中的用户标识符进行匹配,从而将用户登录到您的应用。
关联的帐号登录。
图 1.关联的帐号登录流程。如果用户的设备上有多个已登录的帐号,则用户可能会看到一个帐号选择器,并且只有在选择关联的帐号后才会转到“已关联的帐号登录”视图。

在 Android 应用中实现关联的帐号登录

如需在 Android 应用中支持“已关联的帐号登录”功能,请按照 Android 实现指南中的说明操作。

处理来自 Google 的授权代码请求

Google 会向您的令牌端点发出 POST 请求,以保存您用来交换用户 ID 令牌的授权代码。该请求包含用户的访问令牌和由 Google 签发的 OAuth2 授权代码。

在保存授权代码之前,您必须验证您已向 Google 授予了访问令牌(由 client_id 标识)。

HTTP 请求

示例请求

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

code=GOOGLE_AUTHORIZATION_CODE
&grant_type=urn:ietf:params:oauth:grant-type:reciprocal
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
&access_token=ACCESS_TOKEN

您的令牌交换端点必须能够处理以下请求参数:

令牌端点参数
code 必需的 Google OAuth2 授权代码
client_id 您向 Google 签发的必填客户端 ID
client_secret 您发送给 Google 的必填客户端密钥
access_token 必要:您发送给 Google 的访问令牌。您将使用此参数来获取用户的背景信息
grant_type 必需值必须设置为 urn:ietf:params:oauth:grant-type:reciprocal

您的令牌交换端点应执行以下操作来响应 POST 请求:

  • 验证 access_token 是否已授予 client_id 标识的 Google。
  • 如果请求有效且授权代码成功交换到 Google ID 令牌,则使用 HTTP 200 (OK) 响应进行响应;如果请求无效,则使用 HTTP 错误代码进行响应。

HTTP 响应

成功

返回 HTTP 状态代码 200 OK

成功响应示例
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{}

错误

如果 HTTP 请求无效,请使用以下任一 HTTP 错误代码进行响应:

HTTP 状态代码 车身 说明
400 {"error": "invalid_request"} 请求缺少参数,因此服务器无法继续请求。如果请求包含不受支持的参数或重复了某个参数,也可能会返回此代码
401 {"error": "invalid_request"} 客户端身份验证失败,例如请求中包含无效的客户端 ID 或密钥
401 {"error": "invalid_token"}

在响应标头中添加“WWW-Authentication:Bearer 身份验证”验证

合作伙伴访问令牌无效。
403 {"error": "insufficient_permission"}

在响应标头中添加“WWW-Authentication:Bearer 身份验证”验证

合作伙伴访问令牌未包含执行互惠 OAuth 所需的范围
500 {"error": "internal_error"} 服务器错误

错误响应应包含以下字段:

错误响应字段
error 必填,错误字符串
error_description 易于用户理解的错误说明
error_uri 提供关于错误的更多详细信息的 URI
错误 400 响应示例
HTTP/1.1 400 Bad Request
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
  "error": "invalid_request",
  "error_description": "Request was missing the 'access_token' parameter."
}

交换 ID 令牌的授权代码

您需要将收到的授权代码换成包含用户 Google 帐号相关信息的 Google ID 令牌。

要使用 Google ID 令牌交换授权代码,请调用 https://oauth2.googleapis.com/token 端点并设置以下参数:

请求字段
client_id 必需:从 API 控制台“凭据”页面获取的客户端 ID。这通常是名称为 New Actions on Google App 的凭据
client_secret 必填 从 API 控制台的“凭据”页面获取的客户端密钥
code 必需:在初始请求中发送的授权代码
grant_type 必需 如 OAuth 2.0 规范中所定义,此字段的值必须设置为 authorization_code
示例请求
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=GOOGLE_AUTHORIZATION_CODE
&grant_type=authorization_code
&client_id=GOOGLE_CLIENT_ID
&client_secret=GOOGLE_CLIENT_SECRET

Google 通过返回包含短期访问令牌和刷新令牌的 JSON 对象响应此请求。

响应包含以下字段:

响应字段
access_token Google 签发的访问令牌(您的应用会发送此访问令牌以授权 Google API 请求)
id_token ID 令牌包含用户的 Google 帐号信息。“验证响应”部分详细介绍了如何解码和验证 ID 令牌响应
expires_in 访问令牌的剩余生命周期(以秒为单位)
refresh_token 可用于获取新访问令牌的令牌。刷新令牌会一直有效,直到用户撤消访问权限
scope 此字段的值始终针对“已关联的帐号登录”用例设置为 openid
token_type 返回的令牌类型。目前,此字段的值始终设置为 Bearer
示例响应
HTTP/1.1 200 OK
Content-type: application/json; charset=utf-8

{
  "access_token": "Google-access-token",
  "id_token": "Google-ID-token",
  "expires_in": 3599,
  "token_type": "Bearer",
  "scope": "openid",
  "refresh_token": "Google-refresh-token"
}


POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=Google authorization code
&grant_type=authorization_code
&client_id=Google client id
&client_secret=Google client secret

验证 ID 令牌响应

Validate and decode the JWT assertion

You can validate and decode the JWT assertion by using a JWT-decoding library for your language. Use Google's public keys, available in JWK or PEM formats, to verify the token's signature.

When decoded, the JWT assertion looks like the following example:

{
  "sub": "1234567890",      // The unique ID of the user's Google Account
  "iss": "https://accounts.google.com",        // The assertion's issuer
  "aud": "123-abc.apps.googleusercontent.com", // Your server's client ID
  "iat": 233366400,         // Unix timestamp of the assertion's creation time
  "exp": 233370000,         // Unix timestamp of the assertion's expiration time
  "name": "Jan Jansen",
  "given_name": "Jan",
  "family_name": "Jansen",
  "email": "jan@gmail.com", // If present, the user's email address
  "email_verified": true,   // true, if Google has verified the email address
  "hd": "example.com",      // If present, the host domain of the user's GSuite email address
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/AOh14GjlTnZKHAeb94A-FmEbwZv7uJD986VOF1mJGb2YYQ",
  "locale": "en_US"         // User's locale, from browser or phone settings
}

In addition to verifying the token's signature, verify that the assertion's issuer (iss field) is https://accounts.google.com, that the audience (aud field) is your assigned client ID, and that the token has not expired (exp field).

Using the email, email_verified and hd fields you can determine if Google hosts and is authoritative for an email address. In cases where Google is authoritative the user is currently known to be the legitimate account owner and you may skip password or other challenges methods. Otherwise, these methods can be used to verify the account prior to linking.

Cases where Google is authoritative:

  • email has a @gmail.com suffix, this is a Gmail account.
  • email_verified is true and hd is set, this is a G Suite account.

Users may register for Google Accounts without using Gmail or G Suite. When email does not contain a @gmail.com suffix and hd is absent Google is not authoritative and password or other challenge methods are recommended to verify the user. email_verfied can also be true as Google initially verified the user when the Google account was created, however ownership of the third party email account may have since changed.