以 Google Chat 用户的身份进行身份验证和授权

本指南介绍如何将 OAuth 2.0 用于用户的Google 凭据 访问 Chat API。身份验证和授权 通过用户凭据访问 Chat 扩展,允许 Chat 扩展应用访问用户数据并执行 可以代表经过身份验证的用户执行相应的操作。通过在用户的 该应用就会拥有与该用户相同的权限,并且可以执行操作 就像是那位用户执行了该任务一样

进行身份验证和授权后 通过用户凭据进行 API 调用时,Chat 应用可以执行 以下:

当应用通过用户身份验证执行操作时 (例如创建聊天室),Google Chat 会显示提供方说明消息 ,告诉用户针对 授权用户。

Google Chat 应用为用户创建聊天室。
图 1. Google Chat 应用代表用户创建聊天室时,系统会显示 Google Chat 显示的提供方消息。

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

使用全网域授权来进行身份验证和授权

如果您是域管理员,您可以授予 全网域授权 授权应用的服务账号访问您用户的数据, 需要每位用户给予同意。配置全网域授权后, 该 服务账号可以模拟用户账号。 虽然服务账号用于 全网域授权将模拟用户, 属于用户身份验证。任何需要 您可以使用全网域授权。

使用管理员权限进行身份验证和授权

如果您是网域管理员或拥有管理员权限的委派管理员,则可以通过在适用方法的请求中设置 use_admin_access 字段,对使用管理员权限的 Google Chat API 调用进行身份验证和授权。如需了解详情,请参阅 API 参考文档

请注意,当 Google Chat 应用以管理员权限执行某项操作时,Chat 不会告知用户执行操作的 Chat 应用的名称或授权该应用的管理员的名称,只会告知用户该操作是由其单位的管理员执行的。

前提条件

Java

  • Business 或 Enterprise 有权访问以下内容的 Google Workspace 账号: Google Chat
  • 创建 Google Cloud 项目
  • 启用并配置 Google Chat API,指定一个名称, 图标和说明。
  • 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

Node.js

Apps 脚本

第 1 步:配置 OAuth 权限请求页面,指定范围,并注册您的应用

当您使用 OAuth 2.0 进行授权时,Google 会显示一个同意屏幕,供您 用户,包括项目摘要、项目政策和请求 授权范围。配置应用的 OAuth 权限请求页面 定义 Google 向用户显示的内容和应用审核者的信息,并注册您的应用 以便日后发布

所有使用 OAuth 2.0 的应用都需要配置同意屏幕,不过您只需 需要列出您 Google Workspace 外部人员使用的应用的范围 组织。

  1. 在 Google Cloud 控制台中,点击“菜单”图标 > API 和服务 > OAuth 同意屏幕

    转到 OAuth 同意屏幕

  2. 为应用选择用户类型,然后点击创建

  3. 填写应用注册表单,然后点击保存并继续

  4. 点击添加或移除范围。添加并验证 您的应用所需的授权范围,然后依次点击更新保存并继续

  5. 查看应用注册摘要。点击修改进行更改,或者 点击返回信息中心

第 2 步:在 Google Cloud 控制台中创建 OAuth 客户端 ID 凭据

如需以最终用户身份进行身份验证并访问应用中的用户数据,您需要执行以下操作: 创建一个或多个 OAuth 2.0 客户端 ID。客户端 ID 用于标识 连接到 Google OAuth 服务器。如果您的应用在多个设备上运行 则需要为每个平台(如 Android、iOS 和 Web)创建一个单独的客户端 ID, 不同平台

创建 OAuth 客户端 ID 凭据

选择应用类型,获取有关如何创建 OAuth 客户端 ID 的具体说明:

Web 应用

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > API 和服务 > 凭据

    进入“凭据”页面

  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 点击应用类型 > Web 应用
  4. 名称字段中,输入凭据的名称。此名称仅在 Google Cloud 控制台中显示。
  5. 添加与您的应用相关的已获授权的 URI:
    • 客户端应用 (JavaScript) - 在已获授权的 JavaScript 来源下,点击添加 URI。然后,输入要用于浏览器请求的 URI。这用于标识您的应用可以从哪些网域向 OAuth 2.0 服务器发送 API 请求。
    • 服务器端应用(Java、Python 等) - 在已获授权的重定向 URI 下,点击添加 URI。然后,输入 OAuth 2.0 服务器可向其发送响应的端点 URI。
  6. 点击创建。系统会显示“OAuth 客户端创建”屏幕,其中显示了您的新客户端 ID 和客户端密钥。

    记下客户端 ID。客户端密钥不用于 Web 应用。

  7. 点击 OK。新创建的凭据会显示在 OAuth 2.0 客户端 ID 下。

Android

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > API 和服务 > 凭据

    进入“凭据”页面

  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 依次点击应用类型 > Android
  4. 在“名称”中字段中输入凭据名称。此名称仅在 Google Cloud 控制台中显示。
  5. 在“Package name”中字段中,输入 AndroidManifest.xml 文件中的软件包名称。
  6. 在“SHA-1 证书指纹”中字段中,输入生成的 SHA-1 证书指纹
  7. 点击创建。系统会显示“OAuth 客户端创建”屏幕,其中显示了您的新客户端 ID。
  8. 点击 OK。新创建的凭据会显示在“OAuth 2.0 客户端 ID”下方。

iOS

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > API 和服务 > 凭据

    进入“凭据”页面

  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 点击应用类型 > iOS
  4. 在“名称”中字段中输入凭据名称。此名称仅在 Google Cloud 控制台中显示。
  5. 在“软件包 ID”中字段中,输入应用的 Info.plist 文件中列出的软件包标识符。
  6. 可选:如果您的应用出现在 Apple App Store 中,请输入 App Store ID。
  7. 可选:在“Team ID”(团队 ID)中字段中,输入 10 个字符的唯一字符串,该字符串由 Apple 生成并分配给您的团队。
  8. 点击创建。系统会显示“OAuth 客户端创建”屏幕,其中显示了您的新客户端 ID 和客户端密钥。
  9. 点击 OK。新创建的凭据会显示在“OAuth 2.0 客户端 ID”下方。

Chrome 应用

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > API 和服务 > 凭据

    进入“凭据”页面

  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 点击应用类型 > Chrome 应用
  4. 在“名称”中字段中输入凭据名称。此名称仅在 Google Cloud 控制台中显示。
  5. 在“应用 ID”中字段中,输入您应用的 32 个字符的唯一 ID 字符串。您可以在应用的 Chrome 应用商店网址和 Chrome 应用商店开发者信息中心内找到此 ID 值。
  6. 点击创建。系统会显示“OAuth 客户端创建”屏幕,其中显示了您的新客户端 ID 和客户端密钥。
  7. 点击 OK。新创建的凭据会显示在“OAuth 2.0 客户端 ID”下方。

桌面应用

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > API 和服务 > 凭据

    进入“凭据”页面

  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 依次点击应用类型 > 桌面应用
  4. 名称字段中,输入凭据的名称。此名称仅在 Google Cloud 控制台中显示。
  5. 点击创建。系统会显示“OAuth 客户端创建”屏幕,其中显示了您的新客户端 ID 和客户端密钥。
  6. 点击 OK。新创建的凭据会显示在 OAuth 2.0 客户端 ID 下。

电视和受限输入设备

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > API 和服务 > 凭据

    进入“凭据”页面

  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 依次点击应用类型 > 电视和受限输入设备
  4. 在“名称”中字段中输入凭据名称。此名称仅在 Google Cloud 控制台中显示。
  5. 点击创建。系统会显示“OAuth 客户端创建”屏幕,其中显示了您的新客户端 ID 和客户端密钥。
  6. 点击 OK。新创建的凭据会显示在“OAuth 2.0 客户端 ID”下方。

通用 Windows 平台 (UWP)

  1. 在 Google Cloud 控制台中,依次点击“菜单”图标 > API 和服务 > 凭据

    进入“凭据”页面

  2. 依次点击创建凭据 > OAuth 客户端 ID
  3. 依次点击应用类型 > 通用 Windows 平台 (UWP)
  4. 在“名称”中字段中输入凭据名称。此名称仅在 Google Cloud 控制台中显示。
  5. 在“商店 ID”中字段中,输入您应用的 12 个字符的唯一 Microsoft Store ID 值。您可以在应用的 Microsoft Store 网址和合作伙伴中心内找到此 ID。
  6. 点击创建。系统会显示“OAuth 客户端创建”屏幕,其中显示了您的新客户端 ID 和客户端密钥。
  7. 点击 OK。新创建的凭据会显示在“OAuth 2.0 客户端 ID”下方。

下载客户端密钥 JSON 文件

客户端密钥文件是 OAuth 客户端 ID 的 JSON 表示 供 Chat 应用在检查时 提供凭据

  1. 在 Google Cloud 控制台中,点击“菜单”图标 > API 和服务 > 凭据

    转到“凭据”页面

  2. OAuth 2.0 客户端 ID 下,点击您创建的客户端 ID。

  3. 点击下载 JSON

  4. 将该文件另存为 client_secrets.json

第 3 步:安装 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.oauth-client</groupId>
    <artifactId>google-oauth-client-jetty</artifactId>
    <version>1.34.1</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-oauthlib

Node.js

要将 Google 客户端库和其他所需的依赖项添加到您的 Node.js 项目中,切换到项目的目录并运行以下命令 命令:

npm install "@googleapis/chat" open server-destroy

Apps 脚本

此示例使用 高级 Chat 服务 来调用 Google Chat API。要启用该服务,请执行以下操作: Apps 脚本项目:

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

您可以使用我们的 客户端库

第 4 步:编写调用 Chat API 的脚本

使用 OAuth 授权调用 API 的过程分为多个步骤。在网络或 则通常过程如下:

  1. 应用将用户定向到一个请求访问用户的授权页面 授权范围指定的数据。应用向客户端标识自身 ID 凭据。
  2. 用户审核应用请求的权限,并批准 请求。
  3. Google 的身份验证服务器将浏览器重定向到应用的 HTTP 端点和授权代码。
  4. 应用程序向 Google 的授权服务器发送另一个请求, 使用授权代码交换访问令牌。
  5. 应用使用访问令牌代表用户调用 API。

要详细了解 OAuth 授权流程,请参阅 使用 OAuth 2.0 访问 Google API 指南

以下 Java、Python 和 Node.js 代码示例使用 客户端库 执行 OAuth 授权流程它会打开一个本地 HTTP 服务器 从授权服务器接收授权代码 来交换访问令牌。 在 Apps 脚本代码示例中,此授权流程为 由 Apps 脚本处理。

完成身份验证流程后,脚本使用 Chat API, 然后创建一个聊天室

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.auth.oauth2.Credential;
    import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
    import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
    import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
    import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
    import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
    import com.google.api.client.http.HttpTransport;
    import com.google.api.client.json.JsonFactory;
    import com.google.api.client.json.gson.GsonFactory;
    import com.google.api.client.util.store.FileDataStoreFactory;
    import com.google.api.services.chat.v1.HangoutsChat;
    import com.google.api.services.chat.v1.model.Space;
    
    import java.io.InputStreamReader;
    import java.util.Collection;
    import java.util.Collections;
    
    /**
     * Authenticates with Chat API via user credentials, then creates a Chat space.
     */
    public class App {
        // Application OAuth credentials.
        private static final String KEYS_RESOURCE_URI = "/client_secrets.json";
    
        // Define your app's authorization scopes.
        private static final Collection<String> SCOPES =
            Collections.singleton("https://www.googleapis.com/auth/chat.spaces.create");
    
        // Directory to store user credentials.
        private static final java.io.File DATA_STORE_DIR =
            new java.io.File(System.getProperty("user.home"), ".store/auth-sample-app");
    
        // Global instance of the JSON factory.
        private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
    
        // Global instance of the HTTP transport.
        private static HttpTransport httpTransport;
    
        // Global instance of the DataStoreFactory. The best practice is to make it a single
        // globally shared instance across your application.
        private static FileDataStoreFactory dataStoreFactory;
    
        public static void main( String[] args ) {
            try {
                // Run app.
                httpTransport = GoogleNetHttpTransport.newTrustedTransport();
                dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
                Credential userCredential = authorize();
                Space response = App.createChatSpace(userCredential);
                // Print details about the created space.
                System.out.println(response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * Authorizes the installed application to access user's protected data.
         */
        private static Credential authorize() throws Exception {
            // Load client secrets.
            GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
                new InputStreamReader(App.class.getResourceAsStream("/client_secrets.json")));
            // Set up authorization code flow.
            GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(dataStoreFactory)
                .build();
            // Authorize.
            return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
        }
    
        /**
         * Creates a Chat space.
         */
        private static Space createChatSpace(Credential userCredential) throws Exception {
            // Build the Chat API client and authenticate with the user account.
            HangoutsChat chatService = new HangoutsChat.Builder(
                httpTransport, JSON_FACTORY, userCredential)
                .setApplicationName("auth-sample-app")
                .build();
    
            // Create a Chat space.
            Space space = new Space()
                // To create a named space, set spaceType to SPACE.
                .setSpaceType("SPACE")
                // The user-visible name of the space.
                .setDisplayName("API-made");
            return chatService.spaces().create(space).execute();
        }
    }
    
  3. 在项目的目录中创建一个名为 resources 的新子目录。

  4. 将文件 client_secrets.json 复制到 resources 子目录。

  5. 如需将 Maven 配置为在项目软件包中包含客户端密钥文件,请按以下步骤操作: 修改项目目录中的 pom.xml 文件,并添加以下内容 添加到 <build> 部分:

    <build>
      <!-- ... existing configurations ... -->
      <resources>
        <resource>
          <directory>resources</directory>
        </resource>
      </resources>
    </build>
    
  6. 要将 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_space_create_named.py 的文件中,该文件位于 包含 client_secrets.json 的同一目录:

    from google_auth_oauthlib.flow import InstalledAppFlow
    from googleapiclient.discovery import build
    
    # Define your app's authorization scopes.
    # When modifying these scopes, delete the file token.json, if it exists.
    SCOPES = ["https://www.googleapis.com/auth/chat.spaces.create"]
    
    def main():
      '''
      Authenticates with Chat API via user credentials,
      then creates a Chat space.
      '''
    
      flow = InstalledAppFlow.from_client_secrets_file(
                        'client_secrets.json', SCOPES)
      creds = flow.run_local_server()
    
      # Build a service endpoint for Chat API.
      service = build('chat', 'v1', credentials=creds)
    
      # Use the service endpoint to call Chat API.
      result = service.spaces().create(
    
        # Details about the space to create.
        body = {
    
          # To create a named space, set spaceType to SPACE.
          'spaceType': 'SPACE',
    
          # The user-visible name of the space.
          'displayName': 'API-made'
    
        }
    
      ).execute()
    
      # Prints details about the created space.
      print(result)
    
    if __name__ == '__main__':
      main()
    

Node.js

  1. 将以下代码保存到名为 chat_space_create_named.js 的文件中,该文件位于 保存 Node.js 项目和 client_secrets.json 的同一目录:

    const fs = require('fs');
    const path = require('path');
    const http = require('http');
    const url = require('url');
    const destroyer = require('server-destroy');
    
    const chat = require('@googleapis/chat');
    
    // Application OAuth credentials.
    const keys = require('./client_secrets.json').installed;
    
    // Define your app's authorization scopes.
    // When modifying these scopes, delete the file token.json, if it exists.
    const scopes = ["https://www.googleapis.com/auth/chat.spaces.create"];
    
    // Create a new OAuth2 client with the configured keys.
    const oauth2Client = new chat.auth.OAuth2(
      keys.client_id,
      keys.client_secret,
      'http://localhost:3000'
    );
    
    /**
     * Opens an HTTP server to accept the OAuth callback.
     * In this simple example, the only request to our webserver is to /?code=<code>.
     */
    async function authenticate(scopes) {
      const opn = (await import('open')).default;
    
      return new Promise((resolve, reject) => {
        // Generate the URL for authorization.
        const authorizeUrl = oauth2Client.generateAuthUrl({
          access_type: 'offline',
          scope: scopes.join(' '),
        });
        // Start the HTTP server to listen for the callback.
        const server = http
          .createServer(async (req, res) => {
            try {
              const qs = new url.URL(req.url, 'http://localhost:3000').searchParams;
              res.end('Authentication successful! Please return to the console.');
              server.destroy();
              const { tokens } = await oauth2Client.getToken(qs.get('code'));
              oauth2Client.credentials = tokens;
              resolve(oauth2Client);
            } catch (e) {
              reject(e);
            }
          })
          .listen(3000, () => {
            // Open the browser to the authorize URL to start the workflow.
            opn(authorizeUrl, { wait: false }).then(cp => cp.unref());
          });
        destroyer(server);
      });
    }
    
    /**
     * Authenticates with Chat API via user credentials, then creates a Chat space.
     */
    async function createSpace() {
      // Create the Chat API client and authenticate with the authorized user.
      const chatClient = await chat.chat({
        version: 'v1',
        auth: oauth2Client
      });
    
      // Call the Chat API to create a space.
      const result = await chatClient.spaces.create({
    
        // Details about the space to create.
        requestBody: {
    
          // To create a named space, set spaceType to SPACE.
          'spaceType': 'SPACE',
    
          // The user-visible name of the space.
          'displayName': 'API-made'
    
        }
    
      });
      return result;
    }
    
    // Authenticate the user, execute the function,
    // then print details about the created space.
    authenticate(scopes)
      .then(createSpace)
      .then(console.log);
    

Apps 脚本

  1. 在 Apps 脚本编辑器中,修改文件 appsscript.json 并添加调用 API 所需的 OAuth 范围:

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

    /**
     * Authenticates with Chat API via user credentials, then creates a
     * Chat space.
     */
    function createSpace() {
      try {
        // Details about the space to create.
        // To create a named space, set spaceType to SPACE.
        // The user-visible name of the space is displayName.
        const space = {'displayName': 'API-made', 'spaceType': 'SPACE'};
    
        // Call Chat API with user credentials to create the space.
        const result = Chat.Spaces.create(space);
    
        // Log details about the created space.
        console.log(result);
      } catch (err) {
        // TODO (developer) - Handle exception
        console.log('Failed to create space with error %s', err.message);
      }
    }
    

第 5 步:运行示例脚本

要运行该示例,请从命令行导航到 您的项目文件,然后执行以下命令:

Java

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

Python

python3 chat_space_create_named.py

Node.js

node chat_space_create_named.js

Apps 脚本

在 Apps 脚本中打开 ChatSpaceCreateNamed.gs 文件 Editor,然后点击 Run

系统会打开一个浏览器,并提示您登录 Google 账号:

正在登录以授权 Chat 应用。

图 2. OAuth 权限请求页面,您可以在其中选择要对应用进行身份验证的账号。

登录后,系统会显示 OAuth 同意屏幕,并要求您授予 授予该应用的权限。

在您授予权限后,脚本会调用 Chat API,该 API 通过创建 显示名称为“API-made”的 Chat 聊天室。控制台会输出 API 调用的详细信息如要查找聊天室,请前往以下位置的聊天室面板: Google Chat。

排查示例问题

运行 chat_space_create_named.py 时,您可能会收到以下错误消息:

Expected a JSON object with a single property for a "web" or "installed" application

此错误消息表示您下载的 client_secrets.json 文件 不以 "web""installed" 开头 属性。使用下载的文件进行身份验证后(如果您的代码无法获得) 将访问令牌保存在新文件(如 token.json)中, 写入 client_secrets.json,在后续使用时可能会导致此错误 尝试进行预授权

如需解决此错误,请从 Google Cloud 控制台下载客户端密钥文件 并将新文件保存到当前文件的位置。

  • 如果您的应用需要继续使用范围外的用户令牌 可以存储令牌,以便日后重复使用。在此示例中 您的应用需要安全地处理用户令牌并处理刷新 令牌撤消和到期。如需了解详情,请参阅 使用 OAuth 2.0 最佳做法指南

  • 查看 Chat API 的其他功能 Chat API 参考文档