欢迎使用 Google Home 开发者中心,您可以在这里学习有关如何开发智能家居 Action 的新平台。注意:你将继续在 Actions 控制台中构建操作。

实现 OAuth 2.0 服务器

使用集合让一切井井有条 根据您的偏好保存内容并对其进行分类。

每个smart home Action must include a mechanism for authenticating users.

通过身份验证,您可以将用户的 Google 帐号与身份验证系统中的用户帐号相关联。这样,您就可以在你的执行方式收到智能家居 intent 时识别用户。Google 智能家居仅支持采用授权代码流的 OAuth。

本页面介绍了如何设置 OAuth 2.0 服务器,使其可与 smart home 操作配合使用。

授权代码流

授权代码流程的 OAuth 2.0 服务器实现包含两个端点,您的服务可通过 HTTPS 提供这两个端点。第一个端点是授权端点,负责查找数据或征得用户同意来访问数据。授权端点会向尚未登录的用户显示登录界面,并记录是否同意请求的访问权限。第二个端点是令牌交换端点,用于获取加密令牌(称为令牌),这些令牌可授权用户访问您的服务。

当 Google 应用需要调用您的某个服务 API 时,Google 会结合使用这些端点来向用户请求代表他们调用这些 API 的权限。

由 Google 发起的 OAuth 2.0 授权代码流程会话具有以下流程:

  1. Google 会在用户的浏览器中打开您的授权端点。如果 Action 在纯语音设备上启动了相应 Action,Google 会将执行操作传输到手机。
  2. 用户登录(如果尚未登录),并授予 Google 使用您的 API 访问其数据的权限(如果他们尚未授予权限)。
  3. 您的服务会创建一个授权代码并将其返回给 Google。为此,请使用附加到请求中的授权代码将用户浏览器重定向回 Google。
  4. Google 将授权代码发送到您的令牌交换端点,该端点会验证代码的真实性并返回访问令牌刷新令牌。访问令牌是服务接受的用于访问 API 的短期令牌。刷新令牌是长期令牌,Google 可以存储该令牌并用于在到期时获取新的访问令牌。
  5. 在用户完成帐号关联流程后,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

为了让授权端点能够处理登录请求,请执行以下步骤:

  1. 验证 client_id 与您为 Google 分配的客户端 ID 是否一致,以及 redirect_uri 是否与 Google 为您的服务提供的重定向网址匹配。这些检查非常重要,可防止授予对意外或配置错误的客户端应用的访问权限。如果您支持多个 OAuth 2.0 流程,还应确认 response_typecode
  2. 检查用户是否已登录您的服务。如果用户未登录,请完成服务的登录或注册流程。
  3. 生成授权代码,供 Google 用于访问您的 API。授权代码可以是任何字符串值,但必须以唯一方式表示用户、令牌的客户端和代码的到期时间,并且不可猜测。您通常会颁发在大约 10 分钟后过期的授权代码。
  4. 确认 redirect_uri 参数指定的网址采用以下格式:
      https://oauth-redirect.googleusercontent.com/r/YOUR_PROJECT_ID
      https://oauth-redirect-sandbox.googleusercontent.com/r/YOUR_PROJECT_ID
      
  5. 将用户的浏览器重定向到由 redirect_uri 参数指定的网址。通过附加 codestate 参数进行重定向时,请包含您刚刚生成的授权代码以及未经修改的原始状态值。以下是生成的网址的示例:
    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_coderefresh_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_codecode 的值为您之前授予 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 请求:

  1. 验证 client_id 是否将请求来源标识为已获授权的来源,以及 client_secret 是否与预期值匹配。
  2. 验证授权代码有效且未过期,请求中指定的客户端 ID 与授权代码关联的客户端 ID 一致。
  3. 确认 redirect_uri 参数指定的网址与初始授权请求中使用的值完全相同。
  4. 如果您无法验证上述所有条件,则返回正文为 {"error": "invalid_grant"} 的 HTTP 400 Bad Request 错误。
  5. 否则,请使用授权代码中的 User-ID 生成刷新令牌和访问令牌。这些令牌可以是任何字符串值,但必须以唯一性表示令牌和令牌对应的用户,且不得猜测。对于访问令牌,还应记录令牌的过期时间,通常是在您发出令牌后一小时。刷新令牌不会过期。
  6. 在 HTTPS 响应的正文中返回以下 JSON 对象:
    {
    "token_type": "Bearer",
    "access_token": "ACCESS_TOKEN",
    "refresh_token": "REFRESH_TOKEN",
    "expires_in": SECONDS_TO_EXPIRATION
    }
    

Google 会为用户存储访问令牌和刷新令牌,并记录访问令牌的有效期。访问令牌到期后,Google 会使用刷新令牌从令牌交换端点获取新的访问令牌。

使用刷新令牌交换访问令牌

访问令牌到期后,Google 会向令牌交换端点发送请求,以刷新令牌换取新的访问令牌。

对于这些请求,grant_type 的值为 refresh_tokenrefresh_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 请求:

  1. 验证 client_id 是否将请求来源标识为 Google,以及 client_secret 是否与预期值匹配。
  2. 验证刷新令牌是否有效,以及请求中指定的客户端 ID 是否与刷新令牌关联的客户端 ID 一致。
  3. 如果您无法验证上述所有条件,则返回正文为 {"error": "invalid_grant"} 的 HTTP 400 Bad Request 错误。
  4. 否则,请使用刷新令牌中的用户 ID 生成访问令牌。这些令牌可以是任何字符串值,但必须唯一表示令牌的用户和客户端,并且不得猜测。对于访问令牌,还应记录令牌的到期时间,通常是在您发出令牌后一小时。
  5. 在 HTTPS 响应的正文中返回以下 JSON 对象:
    {
    “token_type”:
    “Bearer”、
    “access_token”:
    “ACCESS_TOKEN”;
    “expires_in”:
    SECONDS_TO_EXPIRATION
    }

处理 userinfo 请求

userinfo 端点是受 OAuth 2.0 保护的资源,会返回有关关联用户的声明。实现和托管 userinfo 端点是可选的,但以下用例除外:

成功从您的令牌端点检索到访问令牌后,Google 向您的 userinfo 端点发送请求,以检索关于关联用户的基本个人资料信息。

userinfo 端点请求标头
Authorization header Bearer 类型的访问令牌。

例如,如果您的 userinfo 端点在 https://myservice.example.com/userinfo 处可用,则请求可能如下所示:

GET /userinfo HTTP/1.1
Host: myservice.example.com
Authorization: Bearer ACCESS_TOKEN

如需让您的 userinfo 端点处理请求,请执行以下步骤:

  1. 从授权标头中提取访问令牌,并返回与访问令牌相关联的用户的信息。
  2. 如果访问令牌无效,使用 WWW-Authenticate 响应标头会返回 HTTP 401 Unauthorized 错误。下面是 userinfo 错误响应的示例:
    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: error="invalid_token",
    error_description="The Access Token expired"
    
    如果在关联过程中返回 401 Unauthorized 或任何其他失败的错误响应,该错误将无法恢复,检索到的令牌将会被舍弃,用户需要再次启动关联流程。
  3. 如果访问令牌有效,请在 HTTPS 响应的正文中返回以下 JSON 对象并相应地返回 HTTP 200 响应:

    {
    "sub": "USER_UUID",
    "email": "EMAIL_ADDRESS",
    "given_name": "FIRST_NAME",
    "family_name": "LAST_NAME",
    "name": "FULL_NAME",
    "picture": "PROFILE_PICTURE",
    }
    
    如果您的 userinfo 端点返回 HTTP 200 成功响应,则系统会将检索到的令牌和声明注册到用户的 Google 帐号。

    userinfo 端点响应
    sub 用于识别系统中用户的唯一 ID。
    email 用户的电子邮件地址。
    given_name 可选:用户的名字。
    family_name 可选:用户的姓氏。
    name 可选:用户的全名。
    picture 可选:用户的个人资料照片。