使用 OAuth 和 Google Sign-In 简化链接

概述

基于OAuth的谷歌登录在流线型联增加了谷歌登录在之上OAuth的链接。这为 Google 用户提供了无缝链接体验,并且还为使用非 Google 身份注册到您的服务的用户启用了帐户链接。

要使用 OAuth 和 Google Sign-In 执行帐户关联,请按照以下常规步骤操作:

  1. 首先,请用户同意访问他们的 Google 个人资料。
  2. 使用他们的个人资料中的信息检查用户帐户是否存在。
  3. 对于现有用户,链接帐户。
  4. 如果您在身份验证系统中找不到 Google 用户的匹配项,请验证从 Google 收到的 ID 令牌。然后,您可以根据 ID 令牌中包含的配置文件信息创建用户。

图3。使用简化链接在用户手机上进行帐户链接

帐户使用行业标准的OAuth 2.0隐式授权码流相关。您的服务必须支持2.0标准的OAuth授权令牌交换端点。此外,您的令牌交换终结点应该支持JSON网络令牌(JWT)的断言和实施checkcreateget意图。

获取您的 Google API 客户端 ID 和密钥

您需要使用您在完成创建的项目,让您的API客户端ID和秘密的OAuth链接步骤。为此,请完成以下步骤:

  1. 打开的凭据谷歌API控制台
  2. 创建或选择一个 Google API 项目。

    如果你的项目没有为Web应用程序类型客户端ID,单击创建证书> OAuth用户端ID创建一个。一定要包括你的网站的域名在授权JavaScript源框。当您执行本地测试或开发,你必须同时添加http://localhosthttp://localhost:<port_number>授权JavaScript源领域。

实施您的 OAuth 服务器

检查现有的用户帐户

用户同意访问其Google个人资料后,Google会发送请求,其中包含对Google用户身份的签名声明。断言包含的信息包括用户的Google帐户ID,名称和电子邮件地址。为您的项目配置的令牌交换端点处理该请求。

如果您的身份验证系统中已经存在相应的Google帐户,则令牌交换端点将使用account_found=true响应。如果Google帐户与现有用户不匹配,则令牌交换端点将返回一个HTTP 404 Not Found错误,带有account_found=false

该请求具有以下形式:

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

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

令牌端点参数
intent对于这些请求,此参数的值为check
grant_type交换令牌的类型。对于这些请求,此参数的值为urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JSON Web令牌(JWT),提供对Google用户身份的签名断言。 JWT包含的信息包括用户的Google帐户ID,名称和电子邮件地址。

当您的令牌交换端点接收到check请求时,它需要验证和解码JWT断言。

验证并解码JWT断言

您可以使用针对您的语言JWT解码库来验证和解码JWT断言。使用Google的JWKPEM格式的公钥来验证令牌的签名。

解码后,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场地)。

使用emailemail_verifiedhd字段,您可以确定Google是否托管电子邮件地址并对其具有权威性。如果Google具有权威性,则当前已知该用户为合法帐户所有者,您可以跳过密码或其他挑战方法。否则,可以使用这些方法在链接之前验证帐户。

Google具有权威性的情况:

  • email后缀为@gmail.com ,这是一个Gmail帐户。
  • email_verified为true并且设置了hd ,这是一个G Suite帐户。

用户可以在不使用Gmail或G Suite的情况下注册Google帐户。如果email不包含@gmail.com后缀,并且没有hd则Google并不具有权威性,建议您使用密码或其他验证方法来验证用户。当Google在创建Google帐户时最初验证了用户时, email_verfied也可能为true,但是此后第三方电子邮件帐户的所有权可能已更改。

检查您的身份验证系统中是否已存在Google帐户

检查以下条件之一是否成立:

  • 在断言的sub字段中找到的Google帐户ID在您的用户数据库中。
  • 断言中的电子邮件地址与您的用户数据库中的用户匹配。

如果任一条件为真,则用户已经注册。在这种情况下,返回如下响应:

HTTP/1.1 200 Success
Content-Type: application/json;charset=UTF-8

{
  "account_found":"true",
}

然后,Google向用户显示一个链接同意对话框,并请求同意所需的范围,以便继续进行链接。 Google征得用户同意后,Google get向您的令牌端点发送一个get请求,以继续进行链接。

如果断言中指定的Google帐户ID或电子邮件地址都不匹配您数据库中的用户,则该用户尚未注册。在这种情况下,令牌交换端点需要使用HTTP 404错误进行响应,该错误指定为"account_found": "false" ,如以下示例所示:

HTTP/1.1 404 Not found
Content-Type: application/json;charset=UTF-8

{
  "account_found":"false",
}
当Google收到带有"account_found": "false"错误的404错误响应时,Google会向用户显示一个对话框,以请求同意创建新帐户并访问所需的范围。 Google征得用户同意后,Google会使用设置为intent参数的值调用您的令牌交换端点,以create该令牌,并包括一个ID令牌,该令牌包含请求中的用户个人资料信息。

处理自动链接

用户同意访问其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

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

令牌端点参数
intent对于这些请求,此参数的值为get
grant_type交换令牌的类型。对于这些请求,此参数的值为urn:ietf:params:oauth:grant-type:jwt-bearer
assertion JSON Web令牌(JWT),提供对Google用户身份的签名断言。 JWT包含的信息包括用户的Google帐户ID,名称和电子邮件地址。
scope可选:您已配置Google来向用户请求的所有范围。

当您的令牌交换端点接收到链接请求时,它需要验证并解码JWT断言。

验证并解码JWT断言

您可以使用针对您的语言JWT解码库来验证和解码JWT断言。使用Google的JWKPEM格式的公钥来验证令牌的签名。

解码后,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场地)。

使用emailemail_verifiedhd字段,您可以确定Google是否托管电子邮件地址并对其具有权威性。如果Google具有权威性,则当前已知该用户为合法帐户所有者,您可以跳过密码或其他挑战方法。否则,可以使用这些方法在链接之前验证帐户。

Google具有权威性的情况:

  • email后缀为@gmail.com ,这是一个Gmail帐户。
  • email_verified为true并且设置了hd ,这是一个G Suite帐户。

用户可以在不使用Gmail或G Suite的情况下注册Google帐户。如果email不包含@gmail.com后缀,并且没有hd则Google并不具有权威性,建议您使用密码或其他验证方法来验证用户。当Google在创建Google帐户时最初验证了用户时, email_verfied也可能为true,但是此后第三方电子邮件帐户的所有权可能已更改。

检查您的身份验证系统中是否已存在Google帐户

检查以下条件之一是否成立:

  • 在断言的sub字段中找到的Google帐户ID在您的用户数据库中。
  • 断言中的电子邮件地址与您的用户数据库中的用户匹配。

在某些情况下,对于用户而言,基于ID令牌的帐户链接可能会失败。如果出于某种原因这样做,则令牌交换端点需要使用HTTP 401错误进行响应,该错误指定error=linking_error ,如以下示例所示:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}
当Google收到带有linking_error的401错误响应时,Google会在请求中使用以下内容调用您的令牌交换端点:

  • 设置要createintent参数
  • 具有ID令牌和用户个人资料信息的JWT

通过 Google Sign-In 处理帐户创建

当用户需要创建您的服务帐户,谷歌发出请求到您的令牌交换端点,指出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

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

令牌端点参数
intent对于这些请求,这个参数的值是create
grant_type正在交换的令牌类型。对于这些请求,这个参数的值是urn:ietf:params:oauth:grant-type:jwt-bearer
assertion一个 JSON 网络令牌 (JWT),提供 Google 用户身份的签名断言。 JWT 包含的信息包括用户的 Google 帐户 ID、姓名和电子邮件地址。

在中智威汤逊assertion参数包含用户的谷歌帐户ID,姓名和电子邮件地址,你可以用它来创建你的服务的新帐户。

要响应帐户创建请求,您的令牌交换端点必须执行以下两个部分中的步骤。

验证并解码JWT断言

您可以使用针对您的语言JWT解码库来验证和解码JWT断言。使用Google的JWKPEM格式的公钥来验证令牌的签名。

解码后,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场地)。

使用emailemail_verifiedhd字段,您可以确定Google是否托管电子邮件地址并对其具有权威性。如果Google具有权威性,则当前已知该用户为合法帐户所有者,您可以跳过密码或其他挑战方法。否则,可以使用这些方法在链接之前验证帐户。

Google具有权威性的情况:

  • email后缀为@gmail.com ,这是一个Gmail帐户。
  • email_verified为true并且设置了hd ,这是一个G Suite帐户。

用户可以在不使用Gmail或G Suite的情况下注册Google帐户。如果email不包含@gmail.com后缀,并且没有hd则Google并不具有权威性,建议您使用密码或其他验证方法来验证用户。当Google在创建Google帐户时最初验证了用户时, email_verfied也可能为true,但是此后第三方电子邮件帐户的所有权可能已更改。

验证用户信息并创建新帐户

检查以下任一条件是否为真:

  • 该谷歌帐户ID,在断言的发现sub场,是在你的用户数据库。
  • 断言中的电子邮件地址与您的用户数据库中的用户相匹配。

如果任一条件为真,则提示用户将其现有帐户与其 Google 帐户相关联。为此,请求与响应HTTP 401错误指定error=linking_error并给用户的电子邮件地址作为login_hint 。以下是响应示例:

HTTP/1.1 401 Unauthorized
Content-Type: application/json;charset=UTF-8

{
  "error":"linking_error",
  "login_hint":"foo@bar.com"
}

当谷歌收到401错误响应linking_error ,谷歌会将用户带到你的授权端点login_hint作为参数。用户使用浏览器中的 OAuth 链接流程完成帐户链接。

如果这两个条件都不成立,请使用 JWT 中提供的信息创建一个新用户帐户。新帐户通常没有密码设置。建议您将 Google Sign-In 添加到其他平台,以使用户能够在您的应用程序的各个方面使用 Google 登录。或者,您可以通过电子邮件向用户发送启动密码恢复流程的链接,以允许用户设置密码以在其他平台上登录。

当完成创作,发出一个访问令牌 和刷新令牌 并在HTTPS响应的主体在下面的例子中JSON对象返回的值,比如:

{
  "token_type": "Bearer",
  "access_token": "ACCESS_TOKEN",

  "refresh_token": "REFRESH_TOKEN",

  "expires_in": SECONDS_TO_EXPIRATION
}

验证您的实施

You can validate your implementation by using the OAuth 2.0 Playground tool.

In the tool, do the following steps:

  1. Click Configuration to open the OAuth 2.0 Configuration window.
  2. In the OAuth flow field, select Client-side.
  3. In the OAuth Endpoints field, select Custom.
  4. Specify your OAuth 2.0 endpoint and the client ID you assigned to Google in the corresponding fields.
  5. In the Step 1 section, don't select any Google scopes. Instead, leave this field blank or type a scope valid for your server (or an arbitrary string if you don't use OAuth scopes). When you're done, click Authorize APIs.
  6. In the Step 2 and Step 3 sections, go through the OAuth 2.0 flow and verify that each step works as intended.

You can validate your implementation by using the Google Account Linking Demo tool.

In the tool, do the following steps:

  1. Click the Sign-in with Google button.
  2. Choose the account you'd like to link.
  3. Enter the service ID.
  4. Optionally enter one or more scopes that you will request access for.
  5. Click Start Demo.
  6. When prompted, confirm that you may consent and deny the linking request.
  7. Confirm that you are redirected to your platform.