作为 Google Chat 应用进行身份验证

本指南介绍了如何设置和使用服务帐号,以便代表 Chat 应用访问 Google Chat API。首先,引导您创建服务帐号。然后介绍如何编写脚本,使用服务帐号通过 Chat API 进行身份验证,并在 Chat 聊天室中发布消息。

异步调用 Google Chat API 时,聊天应用可以使用服务帐号进行身份验证,这样它们就可以:

  • 使用 spaces.messages.create 向 Google Chat 发送消息,以便:
    • 在长时间运行的后台作业运行完毕后通知用户。
    • 提醒用户服务器已下线。
    • 请客户服务人员处理新开设的客户案例。
  • 使用 spaces.messages.update 将之前发送的消息更新为:
    • 更改正在进行的操作的状态。
    • 更新任务的分配对象或截止日期。
  • 使用 spaces.members.list 列出聊天室中的用户,以便:
    • 查看聊天室中的成员。
    • 验证聊天室成员资格包括团队中的所有人。

使用服务帐号进行身份验证时,如需获取 Chat 聊天室相关数据或在其中执行操作,Chat 应用必须具有聊天室中的成员资格。例如,如需列出聊天室的成员或在聊天室中创建消息,Chat 应用本身必须是聊天室的成员。

如果您的 Chat 应用需要访问用户数据或代表用户执行操作,请改为以用户身份进行身份验证

如果您是网域管理员,则可以授予全网域授权,以授权应用的服务帐号访问您用户的数据,而无需取得每位用户的同意。配置全网域授权后,您可以使用您的服务帐号进行 API 调用以模拟用户帐号。虽然使用服务帐号进行身份验证,但全网域授权功能会冒充用户,因此被视为用户身份验证。任何需要用户身份验证的功能都可以使用全网域授权。

如需详细了解 Chat 应用何时需要身份验证以及应使用哪种身份验证,请参阅 Chat API 身份验证和授权概览中的所需身份验证类型

前提条件

如需运行本指南中的示例,您需要满足以下前提条件:

此外,您还需要满足以下特定于语言的前提条件:

Java

  • JDK 1.7 或更高版本
  • Maven 软件包管理工具
  • 已初始化的 Maven 项目。如需初始化新项目,请在命令行界面中运行以下命令:

    mvn archetype:generate -DgroupId=com.google.chat.app.authsample -DartifactId=auth-sample-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
    

Python

  • Python 3.6 或更高版本
  • pip 软件包管理工具

Node.js

  • Node.js
  • npm 软件包管理工具
  • 一个初始化的 Node.js 项目。如需初始化新项目,请创建并切换到新文件夹,然后在命令行界面中运行以下命令:

    npm init
    

Apps 脚本

第 1 步:在 Google Cloud 控制台中创建服务账号

创建您的 Chat 应用可用于访问 Google API 的服务帐号。

创建服务账号

如需创建服务账号,请按照以下步骤操作:

Google Cloud 控制台

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > IAM 和管理 > 服务帐号

    进入“服务账号”

  2. 点击创建服务账号
  3. 填写服务帐号详细信息,然后点击创建并继续
  4. 可选:为您的服务账号分配角色,以授予对 Google Cloud 项目资源的访问权限。如需了解详情,请参阅授予、更改和撤消对资源的访问权限
  5. 点击继续
  6. 可选:输入可以使用此服务账号管理和执行操作的用户或群组。如需了解详情,请参阅管理服务帐号模拟
  7. 点击完成。记下服务帐号的电子邮件地址。

gcloud CLI

  1. 创建服务帐号:
    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
      --display-name="SERVICE_ACCOUNT_NAME"
  2. 可选:为您的服务账号分配角色,以授予对 Google Cloud 项目资源的访问权限。如需了解详情,请参阅授予、更改和撤消对资源的访问权限

服务帐号会显示在服务帐号页面上。接下来,为服务帐号创建一个私钥。

创建一个私钥

如需为服务帐号创建和下载私钥,请按以下步骤操作:

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > IAM 和管理 > 服务帐号

    进入“服务账号”

  2. 选择您的服务帐号。
  3. 依次点击密钥 > 添加密钥 > 创建新密钥
  4. 选择 JSON,然后点击创建

    系统会生成新的公钥/私钥对,并将其作为新文件下载到您的计算机。将下载的 JSON 文件另存为 credentials.json 到您的工作目录中。此文件是此密钥的唯一副本。如需了解如何安全地存储密钥,请参阅管理服务帐号密钥

  5. 点击关闭

如需详细了解服务帐号,请参阅 Google Cloud IAM 文档中的服务帐号

第 2 步:安装 Google 客户端库和其他依赖项

安装项目所需的 Google 客户端库和其他依赖项。

Java

如需将 Google 客户端库和其他所需的依赖项添加到您的 Maven 项目中,请修改项目目录中的 pom.xml 文件并添加以下依赖项:

<dependencies>
  <!-- ... existing dependencies ... -->
  <dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-chat</artifactId>
    <version>v1-rev20230905-2.0.0</version>
  </dependency>
  <dependency>
    <groupId>com.google.auth</groupId>
    <artifactId>google-auth-library-oauth2-http</artifactId>
    <version>1.19.0</version>
  </dependency>
  <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.10.1</version>
  </dependency>
</dependencies>

Python

如果尚未安装 Python 版 Google 客户端库,请在命令行界面中运行以下命令:

pip3 install --upgrade google-api-python-client google-auth

Node.js

如需将 Google 客户端库添加到您的 Node.js 项目,请切换到项目的目录,并在命令行界面中运行以下命令:

npm install "@googleapis/chat"

Apps 脚本

此示例使用适用于 Apps 脚本库的 OAuth2 生成用于服务帐号身份验证的 JWT 令牌。如需将该库添加到 Apps 脚本项目,请执行以下操作:

  1. 点击左侧的编辑器
  2. 在左侧的旁边,点击添加库
  3. 输入脚本 ID 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
  4. 点击查询,然后点击添加

此示例使用高级聊天服务调用 Google Chat API。如需为您的 Apps 脚本项目启用该服务,请执行以下操作:

  1. 点击左侧的编辑器
  2. 在左侧的服务旁边,点击添加服务
  3. 选择 Google Chat API
  4. 版本中,选择 v1
  5. 点击添加

您可以使用我们的客户端库支持的任何语言。

第 3 步:编写一个脚本,使用服务账号通过 Chat API 进行身份验证

以下代码会使用服务帐号进行 Chat API 身份验证,然后将消息发布到 Chat 聊天室:

Java

  1. 在项目的目录中,打开文件 src/main/java/com/google/chat/app/authsample/App.java
  2. App.java 中的内容替换为以下代码:

    package com.google.chat.app.authsample;
    
    import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
    import com.google.api.client.http.HttpRequestInitializer;
    import com.google.api.client.json.gson.GsonFactory;
    import com.google.api.services.chat.v1.HangoutsChat;
    import com.google.api.services.chat.v1.model.Message;
    import com.google.auth.http.HttpCredentialsAdapter;
    import com.google.auth.oauth2.GoogleCredentials;
    
    /**
     * Authenticates with Chat API via service account credentials,
     * then creates a Chat message.
     */
    public class App {
        // Specify required scopes.
        private static final String CHAT_SCOPE = "https://www.googleapis.com/auth/chat.bot";
    
        // Specify service account details.
        private static final String PRIVATE_KEY_RESOURCE_URI = "/credentials.json";
    
        public static void main( String[] args ) {
            try {
                // Run app.
                Message response = App.createChatMessage();
                // Print details about the created message.
                System.out.println(response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        private static Message createChatMessage() throws Exception {
            // Build the Chat API client and authenticate with the service account.
            GoogleCredentials credentials = GoogleCredentials.fromStream(
                App.class.getResourceAsStream(PRIVATE_KEY_RESOURCE_URI))
                .createScoped(CHAT_SCOPE);
            HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials);
            HangoutsChat chatService = new HangoutsChat.Builder(
                GoogleNetHttpTransport.newTrustedTransport(),
                GsonFactory.getDefaultInstance(),
                requestInitializer)
                .setApplicationName("auth-sample-app")
                .build();
    
            // The space to create the message in.
            //
            // Replace SPACE_NAME with a space name.
            // Obtain the space name from the spaces resource of Chat API,
            // or from a space's URL.
            String spaceName = "spaces/SPACE_NAME";
    
            // Create a Chat message.
            Message message = new Message().setText("Hello, world!");
            return chatService.spaces().messages().create(spaceName, message).execute();
        }
    }
    
  3. 在代码中,将 SPACE_NAME 替换为聊天室名称,您可以通过 Chat API 中的 spaces.list 方法或聊天室的网址获取该名称。

  4. 在项目的目录中创建一个名为 resources 的新子目录。

  5. 确保您服务帐号的私钥文件名为 credentials.json,并将其复制到 resources 子目录。

  6. 如需将 Maven 配置为在项目软件包中包含私钥文件,请修改项目目录中的 pom.xml 文件,并将以下配置添加到 <build> 部分:

    <build>
      <!-- ... existing configurations ... -->
      <resources>
        <resource>
          <directory>resources</directory>
        </resource>
      </resources>
    </build>
    
  7. 如需将 Maven 配置为包含项目软件包中的依赖项并执行应用的主类,请修改项目目录中的 pom.xml 文件,并将以下配置添加到 <plugins> 部分:

    <plugins>
      <!-- ... existing configurations ... -->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.google.chat.app.authsample.App</mainClass>
            </manifest>
          </archive>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
    

Python

  1. 在您的工作目录中,创建一个名为 chat_app_auth.py 的文件。
  2. chat_app_auth.py 中添加以下代码:

    from apiclient.discovery import build
    from google.oauth2 import service_account
    
    # Specify required scopes.
    SCOPES = ['https://www.googleapis.com/auth/chat.bot']
    
    # Specify service account details.
    CREDENTIALS = service_account.Credentials.from_service_account_file(
        'credentials.json', scopes=SCOPES)
    
    # Build the URI and authenticate with the service account.
    chat = build('chat', 'v1', credentials=CREDENTIALS)
    
    # Create a Chat message.
    result = chat.spaces().messages().create(
    
        # The space to create the message in.
        #
        # Replace SPACE_NAME with a space name.
        # Obtain the space name from the spaces resource of Chat API,
        # or from a space's URL.
        parent='spaces/SPACE_NAME',
    
        # The message to create.
        body={'text': 'Hello, world!'}
    
    ).execute()
    
    # Prints details about the created message.
    print(result)
    
  3. 在代码中,将 SPACE_NAME 替换为聊天室名称,您可以通过 Chat API 中的 spaces.list 方法或聊天室的网址获取该名称。确保服务帐号的私钥文件名为 credentials.json

Node.js

  1. 在项目的目录中,创建一个名为 chat_app_auth.js 的文件。
  2. chat_app_auth.js 中添加以下代码:

    const chat = require('@googleapis/chat');
    
    async function createMessage() {
      const auth = new chat.auth.GoogleAuth({
    
        // Specify service account details.
        keyFilename: 'credentials.json',
    
        // Specify required scopes.
        scopes: ['https://www.googleapis.com/auth/chat.bot']
    
      });
      const authClient = await auth.getClient();
    
      // Create the Chat API client and authenticate with the service account.
      const chatClient = await chat.chat({
        version: 'v1',
        auth: authClient
      });
    
      // Create a Chat message.
      const result = await chatClient.spaces.messages.create({
    
        // The space to create the message in.
        //
        // Replace SPACE_NAME with a space name.
        // Obtain the space name from the spaces resource of Chat API,
        // or from a space's URL.
        parent: 'spaces/SPACE_NAME',
    
        // The message to create.
        requestBody: { 'text': 'Hello, world!' }
    
      });
      return result;
    }
    
    // Execute function then print details about the created message.
    createMessage().then(console.log);
    
  3. 在代码中,将 SPACE_NAME 替换为聊天室名称,您可以通过 Chat API 中的 spaces.list 方法或聊天室的网址获取该名称。确保服务帐号的私钥文件名为 credentials.json

Apps 脚本

  1. 在 Apps 脚本编辑器中,修改文件 appsscript.json,并添加发出外部请求以获取服务帐号 OAuth 令牌所需的 OAuth 范围:

      "oauthScopes": [
        "https://www.googleapis.com/auth/script.external_request"
      ]
    
  2. 将以下代码保存到 Apps 脚本项目中名为 ChatAppAuth.gs 的文件中:

    // Specify the contents of the file credentials.json.
    const CREDENTIALS = CREDENTIALS;
    
    const SCOPE = 'https://www.googleapis.com/auth/chat.bot';
    
    // The space to create the message in.
    //
    // Replace SPACE_NAME with a space name.
    // Obtain the space name from the spaces resource of Chat API,
    // or from a space's URL.
    const PARENT = 'spaces/SPACE_NAME'
    
    /**
     * Authenticates with Chat API via app credentials, then posts a message.
     */
    function createMessageWithAppCredentials() {
      try {
        const service = getService_();
        if (!service.hasAccess()) {
          console.error(service.getLastError());
          return;
        }
    
        // Specify the message to create.
        const message = {'text': 'Hello world!'};
    
        // Call Chat API with a service account to create a message.
        const result = Chat.Spaces.Messages.create(
            message,
            PARENT,
            {},
            // Authenticate with the service account token.
            {'Authorization': 'Bearer ' + service.getAccessToken()});
    
        // Log details about the created message.
        console.log(result);
    
      } catch (err) {
        // TODO (developer) - Handle exception.
        console.log('Failed to create message with error %s', err.message);
      }
    }
    
    /**
     * Configures the OAuth library to authenticate with the service account.
     */
    function getService_() {
      return OAuth2.createService(CREDENTIALS.client_email)
          .setTokenUrl('https://oauth2.googleapis.com/token')
          .setPrivateKey(CREDENTIALS.private_key)
          .setIssuer(CREDENTIALS.client_email)
          .setSubject(CREDENTIALS.client_email)
          .setScope(SCOPE)
          .setPropertyStore(PropertiesService.getScriptProperties());
    }
    
  3. 在代码中,将 CREDENTIALS 替换为 credentials.json 文件的内容。

  4. 在代码中,将 SPACE_NAME 替换为聊天室名称,您可以通过 Chat API 中的 spaces.list 方法或聊天室的网址获取该名称。

第 4 步:运行完整示例

在您的工作目录中,构建并运行示例:

Java

mvn compile assembly:single
java -jar target/auth-sample-app-1.0-SNAPSHOT-jar-with-dependencies.jar

Python

python3 chat_app_auth.py

Node.js

node chat_app_auth.js

Apps 脚本

在 Apps 脚本编辑器中打开文件 ChatAppAuth.gs,然后点击运行

您的脚本向 Chat API 发出经过身份验证的请求,该请求通过在 Chat 聊天室中以 Chat 应用的形式发布消息进行响应。

排查示例问题

本部分介绍在尝试运行此示例时可能会遇到的常见问题。

你无权使用此应用

运行脚本时,您可能会收到错误消息:

<HttpError 403 when requesting https://chat.googleapis.com/v1/spaces/{space}/messages?alt=json returned "You are not permitted to use this app". Details: "You are not permitted to use this app">

此错误消息表示 Chat 应用无权在指定的 Chat 聊天室中创建 Chat 消息。

如需解决该错误,请将 Chat 应用添加到脚本中指定的 Chat 聊天室

查看 Chat API 参考文档,了解 Chat API 的其他功能。