使用代码模型

借助 Google Identity Services 库,用户可以请求授权 使用基于浏览器的弹出式窗口或重定向用户体验流程从 Google 获取代码。这个 启动安全的 OAuth 2.0 流程并生成用于调用 代表用户创建 Google API。

OAuth 2.0 授权代码流程摘要:

  • 在浏览器中,通过点击按钮等手势,登录 Google 账号 所有者向 Google 申请授权代码。
  • Google 会作出响应,并将唯一的授权代码发送给 或直接调用 授权代码端点。
  • 您的后端平台托管授权代码端点并接收 代码。验证完成后,此代码将按用户获取和 通过向 Google 令牌端点发出的请求来刷新令牌。
  • Google 验证授权代码,确认发出请求 发放访问令牌和刷新令牌,并返回 来请求获得令牌
  • 您的登录端点接收访问和刷新令牌,安全地存储 刷新令牌以供日后使用

初始化代码客户端

google.accounts.oauth2.initCodeClient() 方法可初始化代码客户端。

您可以选择使用重定向弹出式窗口模式的用户流程。利用重定向模式,您可以托管 OAuth2 授权 端点,而 Google 会将用户代理重定向到此端点, 以网址参数的形式共享授权代码。对于弹出模式,您需要定义一个 回调处理程序,用于将授权代码发送到您的服务器。弹出模式 可以用来提供顺畅的用户体验, 离开您的网站。

如需为以下对象初始化客户端:

  • 重定向用户体验流程,将 ux_mode 设置为 redirect,并将 redirect_uri 添加到您的平台的授权代码端点。值 必须与 OAuth 2.0 的某一授权重定向 URI 完全匹配 您在 API 控制台中配置的客户端。此外,还必须符合我们的 重定向 URI 验证规则

  • 弹出用户体验流程,将 ux_mode 设为 popup,并将 callback 的值设置为 将授权代码发送到您的 平台。

防止 CSRF 攻击

为防止跨站请求伪造 (CSRF) 攻击,功能略有不同 重定向和弹出模式用户体验流程采用了各种技术用于重定向 模式下,系统会使用 OAuth 2.0 state 参数。请参阅 RFC6749 第 10.12 节 跨网站请求伪造 如需详细了解如何生成和验证 state 参数,使用“弹出式窗口”模式时 您在请求中添加自定义 HTTP 标头,然后在服务器上确认 它与预期的值和源相匹配。

选择 UX 模式即可查看显示身份验证代码和 CSRF 处理的代码段:

重定向模式

初始化客户端,以便 Google 将用户的浏览器重定向到您的 身份验证端点,以网址参数的形式共享身份验证代码。

const client = google.accounts.oauth2.initCodeClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  ux_mode: 'redirect',
  redirect_uri: "https://your.domain/code_callback_endpoint",
  state: "YOUR_BINDING_VALUE"
});

初始化一个客户端,用户浏览器会从该客户端接收身份验证代码 Google 并将其发送到您的服务器。

const client = google.accounts.oauth2.initCodeClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  ux_mode: 'popup',
  callback: (response) => {
    const xhr = new XMLHttpRequest();
    xhr.open('POST', code_receiver_uri, true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    // Set custom header for CRSF
    xhr.setRequestHeader('X-Requested-With', 'XmlHttpRequest');
    xhr.onload = function() {
      console.log('Auth code response: ' + xhr.responseText);
    };
    xhr.send('code=' + response.code);
  },
});

触发 OAuth 2.0 代码流程

调用代码客户端的 requestCode() 方法以触发用户流:

<button onclick="client.requestCode();">Authorize with Google</button>

这需要用户登录 Google 账号并同意共享 然后再将授权代码返回至您的 重定向端点或回调处理程序。

授权代码处理

Google 会为每个用户生成一个唯一的授权代码,而该代码会 并在后端服务器上验证

对于弹出模式,由 callback 指定的处理程序,在用户的 会将授权代码中继到由您的平台托管的端点。

对于重定向模式,GET 请求将发送到由 redirect_url,共享网址 code 参数中的授权代码。接收者 收到授权代码:

  • 如果您没有现成的授权端点,请创建 实施,或者

  • 更新您的现有端点以接受 GET 请求和网址 参数。以前,在 PUT 请求中包含 有效负载

授权端点

您的授权代码端点必须使用以下网址查询处理 GET 请求: 字符串参数:

名称
授权用户 用户登录身份验证请求
代码 Google 生成的 OAuth2 授权代码
高清 用户账号的托管域
提示符 用户意见征求对话框
范围 要授权的一个或多个 OAuth2 范围的列表(以空格分隔)
CRSF 状态变量

使用网址参数向名为 auth-code 的端点的 GET 请求示例以及 由 example.com 托管:

Request URL: https://www.example.com/auth-code?state=42a7bd822fe32cc56&code=4/0AX4XfWiAvnXLqxlckFUVao8j0zvZUJ06AMgr-n0vSPotHWcn9p-zHCjqwr47KHS_vDvu8w&scope=email%20profile%20https://www.googleapis.com/auth/calendar.readonly%20https://www.googleapis.com/auth/photoslibrary.readonly%20https://www.googleapis.com/auth/contacts.readonly%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile&authuser=0&hd=example.com&prompt=consent

如果授权代码流由较早的 JavaScript 库启动, 或直接调用 Google OAuth 2.0 端点,系统会使用 POST 请求。

示例 POST 请求中包含作为有效负载的 HTTP 请求正文:

Request URL: https://www.example.com/auth-code
Request Payload: 4/0AX4XfWhll-BMV82wi4YwbrSaTPaRpUGpKqJ4zBxQldU\_70cnIdh-GJOBZlyHU3MNcz4qaw

验证请求

在您的服务器上执行以下操作,以避免 CSRF 攻击。

检查 state 参数的值(适用于重定向模式)。

确认 X-Requested-With: XmlHttpRequest 标头已设置为弹出模式。

然后,您应该继续从 Google 获取刷新令牌和访问令牌 前提是您首先成功验证了授权代码请求。

获取访问令牌和刷新令牌

在您的后端平台收到 Google 的授权代码后, 验证请求,使用授权代码从 进行 API 调用。

按照说明第 5 步:交换授权代码 刷新和访问令牌中的为 Web 服务器使用 OAuth 2.0 应用指南。

管理令牌

您的平台会安全地存储刷新令牌。在以下情况下,系统会删除存储的刷新令牌: 用户账号被移除,或者用户已撤消同意 google.accounts.oauth2.revoke或直接通过 https://myaccount.google.com/permissions.

(可选)您可以考虑使用 RISC 通过跨账号保护用户账号 保护

通常,您的后端平台将使用访问令牌调用 Google API。如果 您的 Web 应用还会直接从用户浏览器调用 Google API, 必须实现一种方式,以便与 Web 应用共享访问令牌, 不在本指南的讨论范围内在采用此方法并使用 适用于 JavaScript 的 Google API 客户端库 使用 gapi.client.SetToken() 暂时在浏览器中存储访问令牌 内存,并启用该库来调用 Google API。