v1.0
This commit is contained in:
commit
3335b4c969
176
SKILL.md
Normal file
176
SKILL.md
Normal file
@ -0,0 +1,176 @@
|
||||
---
|
||||
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 等)
|
||||
Loading…
Reference in New Issue
Block a user