概览
基于 OAuth 的 Google 登录精简关联在 OAuth 关联的基础上添加了 Google 登录。这样可为 Google 用户提供无缝关联体验,还可以创建帐号,使用户能够使用您的 Google 帐号在您的服务上创建新帐号。
如需使用 OAuth 和 Google 登录执行帐号关联,请按以下常规步骤操作:
- 首先,请求用户同意访问其 Google 个人资料。
- 使用用户个人资料中的信息检查用户帐号是否存在。
- 对于现有用户,请关联帐号。
- 如果您在身份验证系统中找不到与 Google 用户匹配的令牌,请验证从 Google 收到的 ID 令牌。然后,您可以根据 ID 令牌中包含的个人资料信息创建用户。
![此图显示了用户通过简化的关联流程关联其 Google 帐号的步骤。第一个屏幕截图显示了用户如何选择要关联的应用。通过第二张屏幕截图,用户可以确认他们是否已使用您的服务现有帐号。第三个屏幕截图可让用户选择想要关联的 Google 帐号。第四个屏幕截图显示了将他们的 Google 帐号与应用相关联的确认信息。第五张屏幕截图显示了已成功在 Google 应用中关联的用户帐号。](https://developers.google.cn/static/identity/account-linking/images/streamlined-linking-flow.png?authuser=6&hl=nl)
图 1. 通过简化的关联在用户的手机上关联帐号
简化关联要求
- 实现基本的网络 OAuth 关联流程。您的服务必须支持符合 OAuth 2.0 规范的授权和令牌交换端点。
- 您的令牌交换端点必须支持 JSON 网络令牌 (JWT) 断言,并实现
check
、create
和get
intent。
实现 OAuth 服务器
令牌交换端点必须支持 check
、create
、get
intent。下面显示了通过帐号关联流程完成的步骤,并指明了调用不同 intent 的时间:
- 用户在您的身份验证系统中是否有帐号?(用户选择“是”或“否”)
- 是 :用户是否使用与其 Google 帐号关联的电子邮件地址登录您的平台?(用户选择“是”或“否”)
- 是 :用户在您的身份验证系统中是否有匹配的帐号?(调用
check intent
进行确认)- 是:如果获取 intent 成功返回,则调用
get intent
并关联帐号。 - 否 :创建新帐号?(用户选择“是”或“否”)
- 是:如果创建 intent 成功返回,则调用
create intent
并关联帐号。 - 否 :网络 OAuth 流程被触发,用户被定向到浏览器,并且用户可以选择使用其他电子邮件地址进行关联。
- 是:如果创建 intent 成功返回,则调用
- 是:如果获取 intent 成功返回,则调用
- 否:系统会触发 Web OAuth 流程,将用户定向到他们的浏览器,并向用户提供使用其他电子邮件地址的选项。
- 是 :用户在您的身份验证系统中是否有匹配的帐号?(调用
- 否 :用户在身份验证系统中是否有匹配的帐号?(调用
check intent
进行确认)- 是:如果获取 intent 成功返回,则调用
get intent
并关联帐号。 - 否:如果创建意图成功返回,则会调用
create intent
并关联帐号。
- 是:如果获取 intent 成功返回,则调用
- 是 :用户是否使用与其 Google 帐号关联的电子邮件地址登录您的平台?(用户选择“是”或“否”)
Check for an existing user account (check intent)
After the user gives consent to access their Google profile, Google sends a request that contains a signed assertion of the Google user's identity. The assertion contains information that includes the user's Google Account ID, name, and email address. The token exchange endpoint configured for your project handles that request.
If the corresponding Google account is already present in your authentication
system, your token exchange endpoint responds with account_found=true
. If the
Google account doesn't match an existing user, your token exchange endpoint
returns an HTTP 404 Not Found error with account_found=false
.
The request has the following form:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=check&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET
Your token exchange endpoint must be able to handle the following parameters:
Token endpoint parameters | |
---|---|
intent |
For these requests, the value of this parameter is
check . |
grant_type |
The type of token being exchanged. For these requests, this
parameter has the value urn:ietf:params:oauth:grant-type:jwt-bearer . |
assertion |
A JSON Web Token (JWT) that provides a signed assertion of the Google user's identity. The JWT contains information that includes the user's Google Account ID, name, and email address. |
client_id |
The client ID you assigned to Google. |
client_secret |
The client secret you assigned to Google. |
To respond to the check
intent requests, your token exchange endpoint must perform the following steps:
- Validate and decode the JWT assertion.
- Check if the Google account is already present in your authentication system.
验证和解码 JWT 断言
您可以使用 适用于您所用语言的 JWT 解码库。使用 Google 的公钥,在 JWK 或 PEM 格式,用于验证 令牌的签名。
解码后,JWT 断言如以下示例所示:
{ "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 }
除了验证令牌的签名之外,还要验证断言的
颁发者(iss
字段)为 https://accounts.google.com
,
(aud
字段)是分配给您的客户端 ID,并且令牌未过期
(exp
字段)。
使用 email
、email_verified
和 hd
字段,您可以确定
Google 负责托管电子邮件地址,并对其具有权威性。如果 Google
权威性 - 用户当前被认定为合法账号所有者
您可以跳过密码或其他验证方法。否则,这些方法
可用于在关联之前验证账号。
Google 具有权威性的情形:
email
的后缀为@gmail.com
,这是一个 Gmail 账号。email_verified
为 true 且hd
已设置,这是 G Suite 账号。
用户无需使用 Gmail 或 G Suite 即可注册 Google 账号。时间
email
不包含 @gmail.com
后缀,且 hd
不存在 Google 不
建议使用权威凭据和密码或其他验证方法进行验证
用户。email_verified
可能为 true,因为 Google 最初验证了
创建 Google 账号后,该用户会获得第三方的所有权,
后,电子邮件账号可能已更改。
Check if the Google account is already present in your authentication system
Check whether either of the following conditions are true:
- The Google Account ID, found in the assertion's
sub
field, is in your user database. - The email address in the assertion matches a user in your user database.
If either condition is true, the user has already signed up. In that case, return a response like the following:
HTTP/1.1 200 Success Content-Type: application/json;charset=UTF-8 { "account_found":"true", }
If neither the Google Account ID nor the email address specified in the
assertion matches a user in your database, the user hasn't signed up yet. In
this case, your token exchange endpoint needs to reply with a HTTP 404 error
that specifies "account_found": "false"
, as in the following example:
HTTP/1.1 404 Not found Content-Type: application/json;charset=UTF-8 { "account_found":"false", }
处理自动链接(获取 intent)
在用户同意访问其 Google 个人资料后,Google 会发送一个请求,其中包含 Google 用户身份的签名断言。该断言包含用户的 Google 帐号 ID、姓名和电子邮件地址。为您的项目配置的令牌交换端点会处理该请求。
如果您的身份验证系统中已存在相应的 Google 帐号,则您的令牌交换端点会返回用户的令牌。如果 Google 帐号与现有用户不匹配,您的令牌交换端点会返回 linking_error
错误和可选的 login_hint
。
请求的格式如下:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&intent=get&assertion=JWT&scope=SCOPES&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET
您的令牌交换端点必须能够处理以下参数:
令牌端点参数 | |
---|---|
intent |
对于这些请求,此参数的值为 get 。 |
grant_type |
要交换的令牌的类型。对于这些请求,此参数的值为 urn:ietf:params:oauth:grant-type:jwt-bearer 。 |
assertion |
一个 JSON Web 令牌 (JWT),用于提供 Google 用户身份的签名断言。JWT 包含用户的 Google 帐号 ID、姓名和电子邮件地址等信息。 |
scope |
可选:您已将 Google 配置为向用户请求的任何范围。 |
client_id |
您分配给 Google 的客户端 ID。 |
client_secret |
您分配给 Google 的客户端密钥。 |
为了响应 get
intent 请求,您的令牌交换端点必须执行以下步骤:
- 验证并解码 JWT 断言。
- 检查您的身份验证系统中是否已存在该 Google 帐号。
验证和解码 JWT 断言
您可以使用 适用于您所用语言的 JWT 解码库。使用 Google 的公钥,在 JWK 或 PEM 格式,用于验证 令牌的签名。
解码后,JWT 断言如以下示例所示:
{ "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 }
除了验证令牌的签名之外,还要验证断言的
颁发者(iss
字段)为 https://accounts.google.com
,
(aud
字段)是分配给您的客户端 ID,并且令牌未过期
(exp
字段)。
使用 email
、email_verified
和 hd
字段,您可以确定
Google 负责托管电子邮件地址,并对其具有权威性。如果 Google
权威性 - 用户当前被认定为合法账号所有者
您可以跳过密码或其他验证方法。否则,这些方法
可用于在关联之前验证账号。
Google 具有权威性的情形:
email
的后缀为@gmail.com
,这是一个 Gmail 账号。email_verified
为 true 且hd
已设置,这是 G Suite 账号。
用户无需使用 Gmail 或 G Suite 即可注册 Google 账号。时间
email
不包含 @gmail.com
后缀,且 hd
不存在 Google 不
建议使用权威凭据和密码或其他验证方法进行验证
用户。email_verified
可能为 true,因为 Google 最初验证了
创建 Google 账号后,该用户会获得第三方的所有权,
后,电子邮件账号可能已更改。
检查您的身份验证系统中是否已存在该 Google 帐号
检查是否满足以下任一条件:
- Google 帐号 ID 可在用户的数据库中找到,可在断言的
sub
字段找到。 - 断言中的电子邮件地址与您的用户数据库中的用户匹配。
如果找到了用户的帐号,请发出访问令牌,并在 HTTPS 响应的正文中以 JSON 对象形式返回值,如以下示例所示:
{ "token_type": "Bearer", "access_token": "ACCESS_TOKEN", "expires_in": SECONDS_TO_EXPIRATION }
在某些情况下,基于 ID 令牌的帐号关联可能会为用户失败。如果出现任何此类情况,您的令牌交换端点都需要使用返回 error=linking_error
的 HTTP 401 错误进行响应,如以下示例所示:
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8 { "error":"linking_error", "login_hint":"foo@bar.com" }
Google 收到包含 linking_error
的 401 错误响应后,会将用户作为授权参数 login_hint
发送到您的授权端点。用户在浏览器中使用 OAuth 关联流程完成帐号关联。
通过 Google 登录功能创建帐号(创建 intent)
当用户需要在您的服务上创建帐号时,Google 会向您的令牌交换端点发出请求,并指定 intent=create
。
请求的格式如下:
POST /token HTTP/1.1 Host: oauth2.example.com Content-Type: application/x-www-form-urlencoded response_type=token&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=SCOPES&intent=create&assertion=JWT&client_id=GOOGLE_CLIENT_ID&client_secret=GOOGLE_CLIENT_SECRET
您的令牌交换端点必须能够处理以下参数:
令牌端点参数 | |
---|---|
intent |
对于这些请求,此参数的值为 create 。 |
grant_type |
要交换的令牌的类型。对于这些请求,此参数的值为 urn:ietf:params:oauth:grant-type:jwt-bearer 。 |
assertion |
一个 JSON Web 令牌 (JWT),用于提供 Google 用户身份的签名断言。JWT 包含用户的 Google 帐号 ID、姓名和电子邮件地址等信息。 |
client_id |
您分配给 Google 的客户端 ID。 |
client_secret |
您分配给 Google 的客户端密钥。 |
assertion
参数中的 JWT 包含用户的 Google 帐号 ID、名称和电子邮件地址,您可以使用这些信息在服务中创建新帐号。
为了响应 create
intent 请求,您的令牌交换端点必须执行以下步骤:
- 验证并解码 JWT 断言。
- 验证用户信息并创建新帐号。
验证和解码 JWT 断言
您可以使用 适用于您所用语言的 JWT 解码库。使用 Google 的公钥,在 JWK 或 PEM 格式,用于验证 令牌的签名。
解码后,JWT 断言如以下示例所示:
{ "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 }
除了验证令牌的签名之外,还要验证断言的
颁发者(iss
字段)为 https://accounts.google.com
,
(aud
字段)是分配给您的客户端 ID,并且令牌未过期
(exp
字段)。
使用 email
、email_verified
和 hd
字段,您可以确定
Google 负责托管电子邮件地址,并对其具有权威性。如果 Google
权威性 - 用户当前被认定为合法账号所有者
您可以跳过密码或其他验证方法。否则,这些方法
可用于在关联之前验证账号。
Google 具有权威性的情形:
email
的后缀为@gmail.com
,这是一个 Gmail 账号。email_verified
为 true 且hd
已设置,这是 G Suite 账号。
用户无需使用 Gmail 或 G Suite 即可注册 Google 账号。时间
email
不包含 @gmail.com
后缀,且 hd
不存在 Google 不
建议使用权威凭据和密码或其他验证方法进行验证
用户。email_verified
可能为 true,因为 Google 最初验证了
创建 Google 账号后,该用户会获得第三方的所有权,
后,电子邮件账号可能已更改。
验证用户信息并创建新帐号
检查是否满足以下任一条件:
- Google 帐号 ID 可在用户的数据库中找到,可在断言的
sub
字段找到。 - 断言中的电子邮件地址与您的用户数据库中的用户匹配。
如果任一条件为 true,请提示用户将其现有帐号与其 Google 帐号相关联。为此,请对请求进行响应,并提供指定 error=linking_error
并将用户的电子邮件地址作为 login_hint
的 HTTP 401 错误。以下是一个示例响应:
HTTP/1.1 401 Unauthorized Content-Type: application/json;charset=UTF-8 { "error":"linking_error", "login_hint":"foo@bar.com" }
Google 收到包含 linking_error
的 401 错误响应后,会将用户作为授权参数 login_hint
发送到您的授权端点。用户在浏览器中使用 OAuth 关联流程完成帐号关联。
如果两个条件都不满足,请使用 JWT 中提供的信息创建新的用户帐号。新帐号通常不会设置密码。建议您将 Google 登录功能添加到其他平台,以便用户能够在应用界面使用 Google 帐号登录。或者,您也可以通过电子邮件向用户发送一个启动密码恢复流程的链接,以便用户设置密码以在其他平台上登录。
创建完成后,发出访问令牌 ,并在 HTTPS 响应的正文中以 JSON 对象形式返回值,如以下示例所示:
{ "token_type": "Bearer", "access_token": "ACCESS_TOKEN", "expires_in": SECONDS_TO_EXPIRATION }
获取 Google API 客户端 ID
在帐号关联注册流程中,您需要提供您的 Google API 客户端 ID。
使用您在完成 OAuth 关联步骤时创建的项目获取 API 客户端 ID。为此,请完成以下步骤:
- 打开 Google API 控制台的凭据页面。
创建或选择 Google API 项目。
如果您的项目没有 Web 应用类型的客户端 ID,请点击创建凭据 > OAuth 客户端 ID 创建一个。请务必在已获授权的 JavaScript 来源框中添加您网站的网域。执行本地测试或开发时,您必须将
http://localhost
和http://localhost:<port_number>
都添加到已获授权的 JavaScript 来源字段中。
验证您的实现
您可以通过使用验证实现的OAuth 2.0游乐场工具。
在工具中,执行以下步骤:
- 单击配置 打开的OAuth 2.0配置窗口。
- 在OAuth流场中,选择客户端。
- 在OAuth端点字段中,选择自定义。
- 在相应字段中指定您的 OAuth 2.0 端点和您分配给 Google 的客户端 ID。
- 在步骤1部分,不要选择任何谷歌范围。相反,将此字段留空或键入对您的服务器有效的范围(如果不使用 OAuth 范围,则输入任意字符串)。当您完成后,单击授权的API。
- 在步骤2和步骤3段,完成OAuth 2.0流程和验证每个步骤按预期工作。
您可以通过验证您的实现谷歌帐户链接演示工具。
在工具中,执行以下步骤:
- 点击登录在与谷歌按钮。
- 选择您要关联的帐户。
- 输入服务标识。
- (可选)输入您将请求访问的一个或多个范围。
- 单击开始演示。
- 出现提示时,确认您可以同意并拒绝链接请求。
- 确认您被重定向到您的平台。