每个 smart home Action 都必须包含用户身份验证机制。
通过身份验证,您可以将用户的 Google 帐号与用户在您的身份验证系统中的帐号相关联。这样,您就可以在您的执行方式收到智能家居 intent 时识别用户。Google 智能家居仅支持包含授权代码流程的 OAuth。
本页面介绍了如何设置 OAuth 2.0 服务器,以使其可与 smart home Action 搭配使用。
通过 OAuth 实现 Google 帐号关联
在授权代码流程中,您需要两个端点:
授权端点,向尚未登录的用户显示登录界面。授权端点还会创建一个短期有效的授权代码,用于记录用户对所请求的访问的同意情况。
令牌交换端点,负责进行两种类型的交换:
- 将授权代码交换为长期刷新令牌和短期访问令牌。这种交换会在用户完成帐号关联流程后发生。
- 将长期刷新令牌交换成短期访问令牌。当 Google 因访问令牌已过期而需要新的访问令牌时,就会发生这种交换。
设计准则
本部分介绍了您为 OAuth 关联流程托管的用户屏幕的设计要求和建议。Google 应用调用该方法后,您的平台会向用户显示登录 Google 页面和帐号关联同意屏幕。用户在同意关联帐号后,会被重定向回 Google 的应用。

要求
- 您必须表明用户的帐号将关联到 Google,而不是 Google Home 或 Google 助理等特定 Google 产品。
- 您必须拥有 Google 授权声明,例如“登录即表示您授权 Google 控制您的设备”。请参阅 Google Home 开发者政策的 Google 设备控制授权部分。
- 如果用户选择不关联,您必须为他们提供返回或取消的途径。
- 您必须打开“网络 OAuth 关联”页面,并确保用户能够清楚使用方法(例如用户名和密码字段)登录其 Google 帐号。不要使用 Google 登录 (GSI) 方法,让用户不必转到“网络 OAuth 关联”页面就可以进行关联。这违反了 Google 政策。
建议
建议您执行以下操作:
显示 Google 的隐私权政策。在同意屏幕上添加指向 Google 隐私权政策的链接。
要分享的数据。使用简明扼要的语言告知用户 Google 需要他们的哪些数据以及原因。
明确的号召性用语。在您的同意屏幕上提供明确的号召性用语,例如“同意并关联”。这是因为用户需要了解他们需要与 Google 分享哪些数据才能关联帐号。
能够解除关联。提供一种供用户解除关联的机制,例如指向其在您平台上帐号设置的网址。或者,您也可以添加指向 Google 帐号的链接,以便用户管理其关联的帐号。
能够更改用户帐号。为用户提供切换帐号的方法。如果用户通常有多个帐号,此功能尤为有用。
- 如果用户必须关闭同意屏幕才能切换帐号,请向 Google 发送可恢复的错误,以便用户通过 OAuth 关联方式登录所需的帐号。
添加徽标。在同意屏幕上显示贵公司的徽标。 根据样式准则放置徽标。如果您还想显示 Google 的徽标,请参阅徽标和商标。

授权代码流程
授权代码流程的 OAuth 2.0 服务器实现包含两个端点,您的服务可通过 HTTPS 提供这两个端点。第一个端点是授权端点,负责查找数据或征得用户同意来访问数据。授权端点会向尚未登录的用户显示登录界面,并记录是否同意请求的访问权限。第二个端点是令牌交换端点,用于获取加密令牌(称为令牌),这些令牌可授权用户访问您的服务。
当 Google 应用需要调用您的某个服务 API 时,Google 会结合使用这些端点来向用户请求代表他们调用这些 API 的权限。
由 Google 发起的 OAuth 2.0 授权代码流程会话具有以下流程:
- Google 会在用户的浏览器中打开您的授权端点。如果 Action 在纯语音设备上启动了相应 Action,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
参数指定的网址与初始授权请求中使用的值完全相同。 - 如果您无法验证上述所有条件,则返回正文为
{"error": "invalid_grant"}
的 HTTP 400 Bad Request 错误。 - 否则,请使用授权代码中的 User-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 一致。
- 如果您无法验证上述所有条件,则返回正文为
{"error": "invalid_grant"}
的 HTTP 400 Bad Request 错误。 - 否则,请使用刷新令牌中的用户 ID 生成访问令牌。这些令牌可以是任何字符串值,但必须唯一表示令牌的用户和客户端,并且不得猜测。对于访问令牌,还应记录令牌的到期时间,通常是在您发出令牌后一小时。
- 在 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 端点处理请求,请执行以下步骤:
- 从授权标头中提取访问令牌,并返回与访问令牌相关联的用户的信息。
- 如果访问令牌无效,使用
WWW-Authenticate
响应标头会返回 HTTP 401 Unauthorized 错误。下面是 userinfo 错误响应的示例:HTTP/1.1 401 Unauthorized WWW-Authenticate: error="invalid_token", error_description="The Access Token expired"
如果在关联过程中返回 401 Unauthorized 或任何其他失败的错误响应,该错误将无法恢复,检索到的令牌将会被舍弃,用户需要再次启动关联流程。 如果访问令牌有效,请在 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
可选:用户的个人资料照片。