将 Google Chat 用户 ID 解析为电子邮件:最小特权方式
Source: Dev.to
如果你已经构建了 Google Chat 机器人,可能会遇到这样的问题:Chat API 会发送一个 membership event,其中只包含用户 ID(例如 users/1154…),却 完全省略了 email 字段。而你的业务逻辑通常需要该电子邮件地址。
- 你可能会尝试使用 People API,但它会返回空字段,因为服务账号没有联系人。
- Admin SDK 可以工作,但默认的服务账号调用会返回 403 Forbidden,因为缺少管理员权限。
- Domain‑Wide Delegation (DwD) 可以让机器人冒充管理员,但授予机器人冒充任何用户的权限就像用大锤子敲坚果一样。
有更好的办法。 通过直接为服务账号分配一个 自定义只读管理员角色,即可安全地解析电子邮件,而无需授予全域的管理员访问权限。
策略
我们不使用 DwD 让服务账号冒充管理员,而是直接将服务账号设为管理员——严格来说是具有自定义角色的 只读 管理员。

已为服务账号分配的读取用户自定义角色。
1. 创建自定义角色
- 打开 Google 管理控制台 → 角色 → 创建自定义角色。
- 为其命名(例如 Read Users)。
- 添加 一个权限:
Admin API Privileges > Users > Read。 - 保存角色。
了解更多关于自定义角色的信息.
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是在使用gcloudCLI 进行冒充时的已知怪癖。正如下方的 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 权限后,它还可以:
- 使用 Admin SDK 搜索用户
- 列出组织单位
全部操作无需超级管理员权限,也不需要域范围委派。
为什么这样更好
- 无需密钥 – 不会将长期有效的 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.

