lark-identify-sender.xiaokui/SKILL.md
2026-04-10 19:54:04 +08:00

177 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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 等)