通过 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 文档和应用的后端代码。

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

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

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

    cd YOUR_WORKING_DIRECTORY/java-docs-samples/appengine-java8/endpoints-v2-backend
    
  2. 在文本编辑器中打开 src/main/java/com/example/echo/Echo.java 文件。

  3. getUserEmail 方法的 @ApiMethod 注释中,将 audiencesclientIds 属性中的 YOUR_OAUTH_CLIENT_ID 替换为您创建的客户端 ID。

    @ApiMethod(
        httpMethod = ApiMethod.HttpMethod.GET,
        authenticators = {EspAuthenticator.class},
        audiences = {"YOUR_OAUTH_CLIENT_ID"},
        clientIds = {"YOUR_OAUTH_CLIENT_ID"}
    )
    public Email getUserEmail(User user) throws UnauthorizedException {
      if (user == null) {
        throw new UnauthorizedException("Invalid credentials");
      }
    
      Email response = new Email();
      response.setEmail(user.getEmail());
      return response;
    }
  4. 保存 Echo.java 文件。

  5. 清理项目,然后构建 API:

    Maven

    mvn clean package

    Gradle

          gradle clean
          gradle build
  6. 重新生成 OpenAPI 文档 openapi.json,使其包含客户端 ID。

    Maven

    mvn endpoints-framework:openApiDocs

    Gradle

    gradle endpointsOpenApiDocs
  7. 确保 Google Cloud CLI (gcloud) 有权访问您在 Google Cloud 上的数据和服务:

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

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

    gcloud endpoints services deploy target/openapi-docs/openapi.json
    
  10. 等待命令完成,然后重新部署应用:

    Maven

    mvn appengine:deploy

    Gradle

    gradle appengineDeploy

配置 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. 在后端代码中,getUserEmail 方法返回您在登录时使用的用户帐号的电子邮件地址。

    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();
}

后续步骤