通过 JavaScript 应用发送经过身份验证的请求

本页面介绍如何通过本地运行的 JavaScript 应用向使用 Cloud Endpoints Frameworks 创建的 REST API 发送经过身份验证的请求。JavaScript 应用演示了如何使用 Google 登录,以及如何在请求中发送 Google ID 令牌以验证用户身份。当 JavaScript 应用发送请求时,Endpoints Frameworks 会在验证用户的身份后,将请求传递给在 App Engine 标准环境中运行的后端代码。

前提条件

要运行示例 JavaScript 应用,请执行以下操作:

  • 找到您为示例 API 创建的 Google Cloud 项目 ID,因为您需要将其添加到示例 JavaScript 代码中。如果您在查找项目 ID 时需要帮助,请参阅列出项目

  • 您需要在本地计算机上搭建一个 Web 服务器,以提供包含 JavaScript 代码的示例 index.html 文件。本页面包含使用 Python 运行简单服务器的步骤,但您可以使用任何网络服务器。

下载示例 JavaScript 客户端代码

  1. 将示例克隆到本地计算机:

    git clone https://github.com/GoogleCloudPlatform/web-docs-samples
    
  2. 切换到包含 JavaScript 客户端的目录:

    cd web-docs-samples/endpoints-frameworks
    

创建 OAuth 2.0 客户端 ID

要设置示例以进行身份验证,您需要在示例 JavaScript 代码和后端代码中配置 OAuth 2.0 客户端 ID。JavaScript 应用使用该客户端 ID 从 Google 的 OAuth 2.0 服务器获取 Google ID 令牌,并在请求中发送 Google ID 令牌。Endpoints Frameworks 使用该客户端 ID 来对 JavaScript 应用在请求中发送的 ID 令牌进行身份验证。

如需创建客户端 ID,请执行以下操作:

  1. 在 Google Cloud Console 中,转到“凭据”页面。

    转到“凭据”页面

  2. 从项目列表中,选择您为示例 API 创建的项目。

  3. 点击创建凭据按钮,然后选择 OAuth 客户端 ID。如果这是您第一次在此项目中创建客户端 ID,请按照子步骤在同意屏幕上设置产品名称;否则,请跳至下一步。

    1. 点击配置同意屏幕按钮。
    2. 应用名称字段中输入一个名称。
    3. 点击保存
  4. 应用类型下,点击网页应用

  5. 已获授权的 JavaScript 来源字段中,输入以下内容:

    http://localhost:8080
    
  6. 点击创建

  7. 复制客户端 ID。您的完整客户端 ID 与以下内容类似,但它是您项目中的 Web 应用所独有的。

    271473851874-mtll5dk2vultovbtilt31hakqbinpuvd.apps.googleusercontent.com

如需详细了解如何创建客户端 ID,请参阅设置 OAuth 2.0

配置后端代码并重新部署

要使用 Endpoints Frameworks 验证从 JavaScript 应用发送的请求,您必须将刚刚创建的客户端 ID 添加到示例代码中,并重新部署更新的 OpenAPI 文档和应用的后端代码。

以下过程假定您已按照 Python 版 Endpoints Frameworks 使用入门中的说明部署了示例 API。在开始以下过程之前,请确保在按照向 API 发送请求中所述向 API 发送请求时获得成功响应。

如需配置后端代码并重新部署,请执行以下操作:

  1. 在克隆 python-docs-samples 代码库的目录中,切换到包含 Python 示例的目录:

    cd YOUR_WORKING_DIRECTORY/python-docs-samples/appengine/standard/endpoints-frameworks-v2/echo
    
  2. 在文本编辑器中打开 main.py 文件。

  3. get_user_email 函数的修饰器中,将 your-oauth-client-id.com 替换为刚刚创建的客户端 ID。

  4. 保存 main.py 文件。

  5. 确保您位于示例主目录中:

    python-docs-samples/appengine/standard/endpoints-frameworks-v2/echo
    
  6. 重新生成 OpenAPI 文档,使其包含客户端 ID。在以下命令中,将 YOUR_PROJECT_ID 替换为您为示例 API 创建的项目。

    python lib/endpoints/endpointscfg.py get_openapi_spec main.EchoApi \
        --hostname YOUR_PROJECT_ID.appspot.com
    

    成功完成后,系统会显示以下消息:

    OpenAPI spec written to ./echov1openapi.json
    
  7. 确保 Google Cloud CLI (gcloud) 有权访问您在 Google Cloud 上的数据和服务:

    gcloud auth login
    
  8. 设置 Google Cloud CLI 的默认项目。将 YOUR_PROJECT_ID 替换为您为示例 API 创建的项目:

    gcloud config set project YOUR_PROJECT_ID
    
  9. 部署更新的 OpenAPI 文档:

    gcloud endpoints services deploy echov1openapi.json
    

    成功完成后,该命令将输出如下所示的行:

    Service Configuration [2018-02-13r2] uploaded for service [example-project-12345.appspot.com]
    
  10. 复制新的服务配置 ID。

  11. 以文本格式打开 app.yaml 文件。用新的服务配置 ID 替换 ENDPOINTS_SERVICE_VERSION 字段的值。例如:

    ENDPOINTS_SERVICE_NAME: example-project-12345.appspot.com
    ENDPOINTS_SERVICE_VERSION: 2018-02-13r2
    
  12. 保存 app.yaml 文件。

  13. 重新部署后端代码:

    gcloud app deploy
    

配置 JavaScript 代码

如需配置 JavaScript 代码,请执行以下操作:

  1. web-docs-samples/endpoints-frameworks 目录中,通过文本编辑器打开 main.js 文件。
  2. initGoogleAuth 函数中,将 YOUR_CLIENT_ID 替换为您创建的客户端 ID。

    function initGoogleAuth (clientId = 'YOUR_CLIENT_ID') {
      gapi.auth2.init({
        client_id: clientId,
        scope: 'https://www.googleapis.com/auth/userinfo.email'
      }).then(() => {
        document.getElementById('sign-in-btn').disabled = false;
      }).catch(err => {
        console.log(err);
      });
    }
  3. sendSampleRequest 函数中,将 YOUR_PROJECT_ID 替换为您为示例 API 创建的项目 ID。

    function sendSampleRequest (projectId = 'YOUR_PROJECT_ID') {
      var user = gapi.auth2.getAuthInstance().currentUser.get();
      var idToken = user.getAuthResponse().id_token;
      var endpoint = `https://${projectId}.appspot.com/_ah/api/echo/v1/email`;
      var xhr = new XMLHttpRequest();
      xhr.open('GET', endpoint + '?access_token=' + encodeURIComponent(idToken));
      xhr.onreadystatechange = function () {
        if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
          window.alert(xhr.responseText);
        }
      };
      xhr.send();
    }

发送经过身份验证的请求

  1. 在您克隆了 web-docs-samples 代码库的目录中,切换到包含 JavaScript 示例的目录:

    cd YOUR_WORKING_DIRECTORY/web-docs-samples/endpoints-frameworks
    
  2. 启动 Web 服务器以在端口 8080 上提供 index.html。以下示例使用 Python 的简单服务器:

    python -m http.server 8080
    
  3. 在浏览器中输入 localhost:8080

    JavaScript 应用会显示两个按钮。

    登录

  4. 点击登录。随即会显示使用 Google 帐号登录页面。

  5. 登录成功后,点击发送示例请求按钮。第一次发送请求时,由于 App Engine 启动,您可能会遇到大约 20 秒的延迟。Endpoints Frameworks 会拦截请求,并使用您在后端代码中配置的客户端 ID 来对请求进行身份验证。如果身份验证成功通过,则会发生以下情况:

    1. Endpoints Frameworks 将请求传递给在 App Engine 上运行的示例后端。

    2. 在后端代码中,get_user_email 方法返回您在登录时使用的用户帐号的电子邮件地址。

    3. JavaScript 客户端显示含有电子邮件地址的对话框。

JavaScript 客户端概览

JavaScript 客户端使用“Google 登录”,该服务可以管理 OAuth 2.0 流程。本部分简要介绍了 JavaScript 客户端代码。

Auth 设置

  1. 加载 Google API 平台库以创建 gapi 对象:

      <script src="https://apis.google.com/js/platform.js?onload=loadAuthClient" async defer></script>
    </head>
  2. Google API 平台库加载后,加载 auth2 库:

    function loadAuthClient () {
      gapi.load('auth2', initGoogleAuth);
    }
  3. 初始化 GoogleAuth 对象:

    function initGoogleAuth (clientId = 'YOUR_CLIENT_ID') {
      gapi.auth2.init({
        client_id: clientId,
        scope: 'https://www.googleapis.com/auth/userinfo.email'
      }).then(() => {
        document.getElementById('sign-in-btn').disabled = false;
      }).catch(err => {
        console.log(err);
      });
    }

初始化 GoogleAuth 对象时,请为该对象配置 OAuth 2.0 客户端 ID 和要指定的其他任何选项。通常,您需要指定访问范围。有了这一范围,您不但可以让应用仅请求访问所需的资源,而且还可以让用户控制其向您的应用授予的访问权限大小。在开始实现 OAuth 2.0 授权之前,我们建议您确定应用需要访问权限的范围。本示例请求访问的范围为 https://www.googleapis.com/auth/userinfo.email,该范围将授予查看用户电子邮件地址的权限。

登录

初始化 GoogleAuth 对象后,您可以通过调用 GoogleAuth 对象的 signIn 函数来提示用户登录:

function signIn () {
  gapi.auth2.getAuthInstance().signIn().then(() => {
    document.getElementById('sign-in-btn').hidden = true;
    document.getElementById('sign-out-btn').hidden = false;
    document.getElementById('send-request-btn').disabled = false;
  }).catch(err => {
    console.log(err);
  });
}

使用 ID 令牌发出请求

当用户完成登录后,可使用用户的 ID 令牌发送带有 Authorization 标头的请求:

function sendSampleRequest (projectId = 'YOUR_PROJECT_ID') {
  var user = gapi.auth2.getAuthInstance().currentUser.get();
  var idToken = user.getAuthResponse().id_token;
  var endpoint = `https://${projectId}.appspot.com/_ah/api/echo/v1/email`;
  var xhr = new XMLHttpRequest();
  xhr.open('GET', endpoint + '?access_token=' + encodeURIComponent(idToken));
  xhr.onreadystatechange = function () {
    if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
      window.alert(xhr.responseText);
    }
  };
  xhr.send();
}

后续步骤