177 lines
5.3 KiB
Markdown
177 lines
5.3 KiB
Markdown
---
|
||
name: lark-identify-sender
|
||
description: |
|
||
识别飞书对话中消息发送者的身份。当你收到飞书用户的消息时,使用此技能获取对方的 user_id 和真实姓名,
|
||
以便进行身份识别和权限判断。
|
||
触发场景:需要知道对面是谁、身份识别、权限检查、用户鉴权。
|
||
---
|
||
|
||
# 识别飞书消息发送者身份
|
||
|
||
## 核心概念
|
||
|
||
飞书有三种用户 ID:
|
||
|
||
| ID 类型 | 格式特征 | 作用域 | 适合做身份识别? |
|
||
|---------|---------|--------|----------------|
|
||
| `user_id` | 短字符串,如 `cb2815b4` | **租户级唯一**,所有 bot 通用 | ✅ 推荐 |
|
||
| `open_id` | 以 `ou_` 开头 | 应用级,不同 bot 看到不同值 | ❌ 不推荐跨应用使用 |
|
||
| `union_id` | 以 `on_` 开头 | 同一开发者下所有应用通用 | ⚠️ 可用但不如 user_id 直接 |
|
||
|
||
**结论:始终使用 `user_id` 作为身份标识。**
|
||
|
||
## 方法一:查询已有用户列表(首选)
|
||
|
||
公司全员的 user_id 已记录在 `/root/.openclaw/skills/lark-send-message-as-bot/vala_users_list.md`。
|
||
|
||
如果你已经知道对方姓名,直接查表获取 user_id:
|
||
|
||
```bash
|
||
cat /root/.openclaw/skills/lark-send-message-as-bot/vala_users_list.md
|
||
```
|
||
|
||
## 方法二:通过飞书 API 用 user_id 查真实姓名
|
||
|
||
### 前置条件
|
||
|
||
- Bot 应用需要有 `contact:user.base:readonly` 权限(在飞书开发者后台开通)
|
||
- Bot 凭证已配置在 `/root/.openclaw/credentials/<agent_name>/config.json`
|
||
|
||
### 步骤
|
||
|
||
#### 1. 获取 tenant_access_token
|
||
|
||
```bash
|
||
APP_ID=$(jq -r '.apps[0].appId' /root/.openclaw/credentials/<agent_name>/config.json)
|
||
APP_SECRET=$(jq -r '.apps[0].appSecret' /root/.openclaw/credentials/<agent_name>/config.json)
|
||
|
||
TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"app_id\":\"$APP_ID\",\"app_secret\":\"$APP_SECRET\"}" \
|
||
| jq -r '.tenant_access_token')
|
||
```
|
||
|
||
#### 2. 用 user_id 查询用户信息
|
||
|
||
```bash
|
||
USER_ID="<目标user_id>"
|
||
|
||
curl -s -X GET "https://open.feishu.cn/open-apis/contact/v3/users/${USER_ID}?user_id_type=user_id" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
| jq '.data.user | {name, en_name, department_ids}'
|
||
```
|
||
|
||
返回示例:
|
||
```json
|
||
{
|
||
"name": "刘庆逊",
|
||
"en_name": "Liu Qingxun",
|
||
"department_ids": ["od-xxxxx"]
|
||
}
|
||
```
|
||
|
||
#### 3. 用 open_id 查询用户信息(如果只有 open_id)
|
||
|
||
```bash
|
||
OPEN_ID="ou_xxxxxxxx"
|
||
|
||
curl -s -X GET "https://open.feishu.cn/open-apis/contact/v3/users/${OPEN_ID}?user_id_type=open_id" \
|
||
-H "Authorization: Bearer $TOKEN" \
|
||
| jq '.data.user | {name, user_id, open_id}'
|
||
```
|
||
|
||
这样可以从 open_id 反查 user_id 和姓名。
|
||
|
||
## 方法三:从收到的消息事件中提取发送者
|
||
|
||
当你通过飞书 bot 收到消息时,消息事件 JSON 中已包含发送者信息:
|
||
|
||
```json
|
||
{
|
||
"sender": {
|
||
"sender_id": {
|
||
"open_id": "ou_xxxx",
|
||
"user_id": "cb2815b4",
|
||
"union_id": "on_xxxx"
|
||
},
|
||
"sender_type": "user",
|
||
"tenant_key": "xxx"
|
||
},
|
||
"message": {
|
||
"message_id": "om_xxxx",
|
||
"chat_type": "p2p",
|
||
"content": "{\"text\":\"你好\"}",
|
||
...
|
||
}
|
||
}
|
||
```
|
||
|
||
从中直接取 `sender.sender_id.user_id` 即可。
|
||
|
||
### 如何拿到事件中的 user_id
|
||
|
||
飞书事件推送是否包含 `user_id` 取决于应用权限:
|
||
|
||
- **有 `contact:user.id:readonly` 权限** → 事件中会包含 `user_id` 字段
|
||
- **没有该权限** → 事件中只有 `open_id`,需要调 API 转换(见方法二第 3 步)
|
||
|
||
> **重要:** 如果你发现事件中 `user_id` 为空,请联系管理员在飞书开发者后台为 bot 应用开通 `contact:user.id:readonly` 权限。
|
||
|
||
## 方法四:通过 lark-cli 查询群成员获取 user_id
|
||
|
||
```bash
|
||
LARKSUITE_CLI_CONFIG_DIR=/root/.openclaw/credentials/<agent_name> \
|
||
lark-cli im chat.members get \
|
||
--params '{"chat_id":"<群的chat_id>","member_id_type":"user_id"}' \
|
||
--as bot
|
||
```
|
||
|
||
返回结果中 `member_id` 即为 `user_id`。
|
||
|
||
## 身份识别实战流程
|
||
|
||
当你收到一条飞书消息需要判断对方身份时:
|
||
|
||
```
|
||
1. 检查消息中是否已带有发送者姓名(系统通常会在消息前加上 "姓名: 消息内容")
|
||
→ 如果有,直接使用
|
||
|
||
2. 如果没有姓名,检查是否有 user_id
|
||
→ 如果有,查 vala_users_list.md 对照表
|
||
→ 如果表中没有,调 contact API 查询(方法二)
|
||
|
||
3. 如果只有 open_id(以 ou_ 开头)
|
||
→ 调 contact API 用 open_id 查 user_id 和姓名(方法二第 3 步)
|
||
|
||
4. 拿到 user_id 后,可用于权限判断
|
||
```
|
||
|
||
## 权限分级参考
|
||
|
||
可在 agent 配置中维护权限表,基于 user_id 进行分级:
|
||
|
||
```json
|
||
{
|
||
"access_levels": {
|
||
"admin": ["cb2815b4", "1da2afbf"],
|
||
"editor": ["2c856846", "63943ebf", "8g42f9b4"],
|
||
"viewer": ["*"]
|
||
}
|
||
}
|
||
```
|
||
|
||
所有 bot 共用同一份 user_id 权限表,无需为每个 bot 单独维护。
|
||
|
||
## 常见问题
|
||
|
||
| 问题 | 原因 | 解决方式 |
|
||
|------|------|---------|
|
||
| 事件中 user_id 为空 | 缺少 `contact:user.id:readonly` 权限 | 在开发者后台开通 |
|
||
| 调 contact API 返回 99991672 | 缺少 `contact:user.base:readonly` 权限 | 在开发者后台开通 |
|
||
| 不同 bot 拿到的 open_id 不同 | 正常行为,open_id 是应用级的 | 改用 user_id |
|
||
|
||
## 安全规则
|
||
|
||
- 禁止在终端明文输出 `appSecret` 或 `accessToken`
|
||
- `<agent_name>` 根据当前 agent 身份确定(如 xiaokui、xiaoxi、xiaoban、xiaobian 等)
|