将 Google Chat 用户 ID 解析为电子邮件:最小特权方式

发布: (2025年12月24日 GMT+8 02:43)
6 min read
原文: Dev.to

Source: Dev.to

Google Workspace Developers profile image
Justin Poehnelt

如果你已经构建了 Google Chat 机器人,可能会遇到这样的问题:Chat API 会发送一个 membership event,其中只包含用户 ID(例如 users/1154…),却 完全省略了 email 字段。而你的业务逻辑通常需要该电子邮件地址。

  • 你可能会尝试使用 People API,但它会返回空字段,因为服务账号没有联系人。
  • Admin SDK 可以工作,但默认的服务账号调用会返回 403 Forbidden,因为缺少管理员权限。
  • Domain‑Wide Delegation (DwD) 可以让机器人冒充管理员,但授予机器人冒充任何用户的权限就像用大锤子敲坚果一样。

有更好的办法。 通过直接为服务账号分配一个 自定义只读管理员角色,即可安全地解析电子邮件,而无需授予全域的管理员访问权限。

策略

我们不使用 DwD 让服务账号冒充管理员,而是直接将服务账号设为管理员——严格来说是具有自定义角色的 只读 管理员。

Read Users Custom Role Assigned to Service Account
已为服务账号分配的读取用户自定义角色。

1. 创建自定义角色

  1. 打开 Google 管理控制台角色创建自定义角色
  2. 为其命名(例如 Read Users)。
  3. 添加 一个权限Admin API Privileges > Users > Read
  4. 保存角色。
    了解更多关于自定义角色的信息.

2. 分配角色

将新创建的自定义角色 直接分配给服务账号的电子邮件地址(例如 my-bot@my-project.iam.gserviceaccount.com)。

3. 本地开发

使用 IAM 服务账号冒充(以服务账号的身份)在本地运行脚本,而不是使用域范围委派(服务账号冒充用户)。这使得本地环境 无需密钥

解决方案

在 Google Cloud 上的生产环境中,您的代码通常会使用 Application Default Credentials (ADC),它会以服务账号的身份进行身份验证。由于服务账号本身已经拥有管理员权限,无需额外的冒充逻辑——API 调用即可直接工作。

本地测试 时,我们通过 服务账号冒充 来临时以机器人身份运行,从而避免使用长期有效的 JSON 密钥。

Bash 脚本 – 本地测试流程

#!/bin/bash
# -------------------------------------------------
# Prerequisites
# -------------------------------------------------
# 1. In Google Cloud IAM, grant your user the role
#    "Service Account Token Creator" on the service account.
# 2. In Google Workspace, create a custom admin role with
#    "Admin API Privileges > Users > Read" and assign it
#    to the service‑account email.
# -------------------------------------------------
# Configuration
# -------------------------------------------------
# Replace with the ID from the Chat API
TARGET_USER_ID="115429828439139643037"
SERVICE_ACCOUNT="your-bot@your-project.iam.gserviceaccount.com"

echo "Generating impersonated access token for $SERVICE_ACCOUNT..."

# 1️⃣ Generate an access token for the service account.
#    We request the admin.directory.user.readonly scope.
ACCESS_TOKEN=$(gcloud auth print-access-token \
    --impersonate-service-account="$SERVICE_ACCOUNT" \
    --scopes="https://www.googleapis.com/auth/admin.directory.user.readonly")

if [[ -z "$ACCESS_TOKEN" ]]; then
    echo "Error: Failed to generate impersonated token."
    exit 1
fi

# 2️⃣ Query Admin SDK
echo "Querying Admin SDK for User ID: $TARGET_USER_ID..."
RESPONSE=$(curl -fs -X GET \
    -H "Authorization: Bearer $ACCESS_TOKEN" \
    -H "Content-Type: application/json" \
    "https://admin.googleapis.com/admin/directory/v1/users/${TARGET_USER_ID}?projection=basic")

# 3️⃣ Parse the output
EMAIL=$(echo "$RESPONSE" | jq -r '.primaryEmail')
echo "Resolved email: $EMAIL"

注意: 警告 --scopes flag may not work as expected and will be ignored for account type impersonated_account 是在使用 gcloud CLI 进行冒充时的已知怪癖。正如下方的 token 负载所示,请求的作用域仍然存在,API 调用能够成功。

示例 access‑token 负载

{
  "issued_to": "108111659397065155772",
  "audience": "108111659397065155772",
  "user_id": "108111659397065155772",
  "scope": "https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/admin.directory.user.readonly",
  "expires_in": 3599,
  "email": "admin-read-test@list-user-emails-test.iam.gserviceaccount.com",
  "verified_email": true,
  "access_type": "online"
}

查询结果

------------------------------------
Success! Resolved to: justin@example.com
------------------------------------

超越电子邮件解析

由于服务账户以自身身份运行,它不仅限于解析 ID。拥有 Users > Read 权限后,它还可以:

全部操作无需超级管理员权限,也不需要域范围委派。

为什么这样更好

  • 无需密钥 – 不会将长期有效的 JSON 密钥文件下载到你的笔记本电脑。
  • 审计追踪 – 管理员审计日志会显示 服务账户 执行了读取操作,而不是被冒充的超级管理员。
  • 最小特权 – 机器人只能读取用户信息,无法删除账户、重置密码或读取 Gmail——这些都是广域委派范围常见的风险。

这种做法既让安全团队满意,又能让机器人正常工作。


Resolving Google Chat User IDs to Emails: The Least Privilege Way © 2025 by Justin Poehnelt is licensed under CC BY‑SA 4.0.

Back to Blog

相关文章

阅读更多 »