--- name: openclaw-feishu-docs-perm-auto description: 自动为飞书文档添加用户权限。每次创建飞书文档(多维表格/文档/电子表格/文件夹/云空间文件/知识库节点等)后自动添加用户权限,或用户反馈文档无权限时补充添加权限。适用于 OpenClaw Agent。 license: MIT metadata: openclaw: emoji: 🔐 author: sadjjk version: "1.0.0" --- # 飞书文档权限自动添加 > 🎯 **一句话总结**:飞书应用创建的文档,用户默认无权限。这个 skill 帮你自动添加权限。 --- ## 前置条件 | 条件 | 说明 | |------|------| | 飞书开发者账号 | 需要有飞书开放平台的开发者权限 | | 企业自建应用 | 已创建或有权创建飞书应用 | | 应用权限 | 应用需开通 `docs:permission.member:create` 权限 | --- ## 变量速查表 | 变量名 | 来源 | 用途 | |--------|------|------| | `$APP_ID` | 配置文件 `channels.feishu.appId` | 应用标识 | | `$APP_SECRET` | 配置文件 `channels.feishu.appSecret` | 应用密钥 | | `$OWNER_OPEN_ID` | 配置文件或会话上下文 | 权限接收者 | | `$TENANT_TOKEN` | API 获取 | 请求鉴权 | | `$FILE_TOKEN` | 创建返回或 URL 解析 | 文档标识 | | `$DOC_TYPE` | URL 路径识别 | 文档类型 | --- ## 第一步:检查配置 ⚠️ ### 1.1 读取配置文件 配置文件位置:`~/.openclaw/openclaw.json` ### 1.2 检查必需字段 在 `channels.feishu` 下查找: | 字段名 | 说明 | 示例值 | 必需性 | |--------|------|--------|--------| | `appId` | 飞书应用 ID | `cli_xxxxxxxx` | ✅ 必需 | | `appSecret` | 飞书应用密钥 | `xxxxxxxx` | ✅ 必需 | | `ownerOpenId` | 用户的 open_id | `ou_xxx` | ⚪ 可选* | > *`ownerOpenId` 在配置文件中可选,但执行时必须有值。若配置文件缺失,从会话上下文提取(格式 `user:ou_xxx` → `ou_xxx`)。 配置示例: ```json { "channels": { "feishu": { "enabled": true, "appId": "cli_xxxxxxxx", "appSecret": "xxxxxxxx", "ownerOpenId": "ou_xxx" } } } ``` ### 1.3 检查应用权限 使用 `feishu_app_scopes()` 查询当前飞书应用已开通的权限列表。 检查返回结果中是否包含 `docs:permission.member:create`: - ✅ 有 → 权限正常,继续下一步 - ❌ 无 → 跳转到 [配置引导流程 C](#c-配置应用权限) > 💡 如检查出有权限,后续可跳过此步骤。 ### 1.4 判断逻辑 根据检查结果,按以下流程处理: ``` ┌─────────────────────────────────────────────────────────┐ │ 检查 appId + appSecret │ │ ├─ ❌ 缺失 → [配置引导流程 A] │ │ └─ ✅ 完整 ↓ │ │ 检查应用权限 docs:permission.member:create │ │ ├─ ❌ 缺失 → [配置引导流程 C] │ │ └─ ✅ 完整 ↓ │ │ 检查 ownerOpenId │ │ ├─ ✅ 配置文件有 → 进入第二步 │ │ ├─ ✅ 会话上下文有 → 提取使用,进入第二步 │ │ └─ ❌ 都没有 → [配置引导流程 B] │ └─────────────────────────────────────────────────────────┘ ``` --- ## 工具调用映射 🛠️ > 明确每个步骤应使用的工具,确保 Agent 能正确执行 | 步骤 | 操作 | 工具 | 说明 | |------|------|------|------| | 1.1 | 读取配置文件 | `read` | 读取 `~/.openclaw/openclaw.json` | | 1.3 | 检查应用权限 | `feishu_app_scopes` | 查询已开通权限列表 | | 2.2 | 获取 tenant_access_token | `exec` | 执行 curl 命令请求 API | | 2.3 | 解析文档 token | 内置逻辑 | 从 URL 或返回值中提取 | | 2.4 | 添加用户权限 | `exec` | 执行 curl 命令请求 API | | 配置写入 | 保存 ownerOpenId | `edit` | 更新 `openclaw.json` | **工具调用示例**: ```bash # 读取配置文件 read("~/.openclaw/openclaw.json") # 检查应用权限 feishu_app_scopes() # 获取 tenant_access_token exec('curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal" ...') # 添加权限 exec('curl -s -X POST "https://open.feishu.cn/open-apis/drive/v1/permissions/..." ...') # 保存配置 edit("~/.openclaw/openclaw.json", oldText, newText) ``` --- ## 第二步:执行权限添加 📋 > 前置条件:第一步检查全部通过 ### 2.1 读取配置 **工具**:`read` ```bash APP_ID="读取到的appId" APP_SECRET="读取到的appSecret" OWNER_OPEN_ID="读取到的ownerOpenId" ``` ### 2.2 获取 tenant_access_token **工具**:`exec` **进度提示**:`[1/4] 获取访问令牌...` **请求**: ```bash 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\" }" ``` **成功返回**: ```json { "code": 0, "msg": "ok", "tenant_access_token": "xxxx", "expire": 5535 } ``` **失败返回**: ```json { "code": 10003, "msg": "app id or app secret is invalid" } ``` **处理**: - ✅ 成功:提取 `tenant_access_token`,继续下一步 - ❌ 失败:提示用户检查 App ID 和 App Secret 是否正确 **token 缓存策略**: | token 类型 | 有效期 | 缓存建议 | |-----------|--------|----------| | `tenant_access_token` | 约 2 小时 | 缓存至会话变量,过期前 5 分钟刷新 | **缓存实现**: - 使用会话级变量存储:`CACHED_TENANT_TOKEN`, `TOKEN_EXPIRE_TIME` - 每次请求前检查:若 `now < TOKEN_EXPIRE_TIME - 300`,直接使用缓存 ### 2.3 获取云文档 token **进度提示**:`[2/4] 解析文档 token...` **来源**: 1. 创建飞书文档后返回的 token 或文档 URL 2. 从用户提供的文档链接解析 **URL 解析规则**: | 文档类型 | URL 示例 | |----------|----------| | 文件夹 | `https://xxx.feishu.cn/drive/folder/【token】` | | 文件 | `https://xxx.feishu.cn/file/【token】` | | 旧版文档 | `https://xxx.feishu.cn/docs/【token】` | | 新版文档 | `https://xxx.feishu.cn/docx/【token】` | | 电子表格 | `https://xxx.feishu.cn/【token】` | | 多维表格 | `https://xxx.feishu.cn/base/【token】` | | 知识空间 | `https://xxx.feishu.cn/wiki/settings/【token】` | | 知识库节点 | `https://xxx.feishu.cn/wiki/【token】` | > ⚠️ 复制 URL 时注意删除末尾多余的 `#` 符号。 **自动识别 doc_type**: | URL 路径特征 | doc_type | |-------------|----------| | `/drive/folder/` | `folder` | | `/file/` | `file` | | `/docs/` | `doc` | | `/docx/` | `docx` | | `/base/` | `bitable` | | `/wiki/` | `wiki` | | 其他(根路径) | `sheet` | **识别逻辑**: 1. 从 URL 提取 token(最后一个路径段,去除 `?` 和 `#` 后的内容) 2. 根据 URL 路径匹配 doc_type 3. 若无法匹配,提示用户提供文档类型 **变量定义**: - `FILE_TOKEN = 获取到的云文档 token` - `DOC_TYPE = 识别到的文档类型` ### 2.4 添加用户权限 **工具**:`exec` **进度提示**:`[3/4] 添加用户权限...` **请求**: ```bash curl -s -X POST "https://open.feishu.cn/open-apis/drive/v1/permissions/{FILE_TOKEN}/members/batch_create?type={DOC_TYPE}" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer {tenant_access_token}" \ -d "{ \"members\": [{ \"member_type\": \"openid\", \"member_id\": \"$OWNER_OPEN_ID\", \"perm\": \"full_access\" }] }" ``` **参数说明**: | 参数 | 来源 | 示例 | |------|------|------| | `{FILE_TOKEN}` | 创建文档时返回或 URL 解析 | `xxxxx` | | `{DOC_TYPE}` | URL 路径自动识别 | `bitable` | | `{tenant_access_token}` | 上一步获取 | `t-xxx` | | `$OWNER_OPEN_ID` | ownerOpenId | `ou_xxx` | **doc_type 可选值**: | 值 | 文档类型 | |----|----------| | `bitable` | 多维表格 | | `docx` | 新版文档 | | `doc` | 旧版文档 | | `sheet` | 电子表格 | | `folder` | 文件夹 | | `file` | 云空间文件 | | `wiki` | 知识库节点 | **成功返回**: ```json { "code": 0, "msg": "Success", "data": { "members": [{ "member_id": "xxxx", "member_type": "openid", "perm": "full_access" }] } } ``` ### 2.5 执行结果反馈 **进度提示**:`[4/4] 完成!` **成功时**: ``` ✅ 权限添加成功! 📄 文档:{文档标题或 token} 🔗 链接:{文档 URL} 👤 权限:完整权限 (full_access) 你现在可以直接访问和编辑这个文档了。 如果配置文件中没有ownerOpenId 并询问 是否需要将 ownerOpenId 写入配置文件中 ``` **失败时**: ``` ❌ 权限添加失败 原因:{错误信息} 解决方案:{具体步骤} 需要帮助?请提供以上信息。 ``` --- ## 使用示例 📝 ### 示例 1:创建多维表格后自动添加权限 **用户**:帮我创建一个多维表格叫「项目进度追踪」 **Agent 执行流程**: ``` [1/3] 创建多维表格... → 调用 feishu_bitable_create_app(name="项目进度追踪") → 返回 app_token: "bascnxxx" [2/3] 添加用户权限... → 触发 feishu-perm-auto skill → 检查配置:appId ✓ appSecret ✓ ownerOpenId ✓ → 获取 tenant_access_token → 调用权限 API 添加 full_access [3/3] 完成! ``` **Agent 回复**: ``` ✅ 多维表格「项目进度追踪」已创建! 🔗 链接:https://xxx.feishu.cn/base/bascnxxx 🔐 已自动为你添加完整权限,可直接访问和编辑 ``` --- ### 示例 2:用户反馈文档无权限 **用户**:这个文档我打不开,提示没权限 https://xxx.feishu.cn/docx/doxcnxxx **Agent 执行流程**: ``` [1/3] 解析文档信息... → URL 解析:token=doxcnxxx, doc_type=docx [2/3] 检查配置并添加权限... → 检查配置:appId ✓ appSecret ✓ ownerOpenId ✓ → 获取 tenant_access_token → 调用权限 API 添加 full_access [3/3] 完成! ``` **Agent 回复**: ``` ✅ 权限添加成功! 📄 文档:doxcnxxx 🔗 链接:https://xxx.feishu.cn/docx/doxcnxxx 👤 权限:完整权限 (full_access) 你现在可以直接访问和编辑这个文档了。 ``` --- ### 示例 3:首次使用,配置缺失 **用户**:帮我创建一个飞书文档 **Agent 执行流程**: ``` [1/2] 检查配置... → 读取 ~/.openclaw/openclaw.json → 发现 channels.feishu.appId 缺失 [2/2] 引导配置... ``` **Agent 回复**: ``` ⚠️ 还没配置飞书应用凭证,需要先设置一下: 📱 获取飞书应用凭证: 1. 打开浏览器,访问:https://open.feishu.cn/app 2. 登录你的飞书账号 3. 点击「创建企业自建应用」或选择已有应用 4. 在左侧菜单找到「凭证与基础信息」 5. 复制以下内容: - App ID(cli_ 开头的字符串) - App Secret(点击「查看」后显示) 请把 App ID 和 App Secret 发给我,格式如下: appId: cli_xxxxxxxx appSecret: xxxxxxxx ``` **用户回复后**: ``` 用户:appId: cli_aabbccdd appSecret: 1234567890abcdef Agent: [1/2] 验证凭证... → 获取 tenant_access_token 成功 ✓ [2/2] 保存配置... → 更新 ~/.openclaw/openclaw.json ``` **Agent 回复**: ``` ✅ 飞书应用配置成功! 现在可以正常使用飞书功能了。需要我帮你创建文档吗? ``` --- ### 示例 4:权限已存在(幂等处理) **用户**:给这个文档加权限 https://xxx.feishu.cn/base/bascnxxx **Agent 执行流程**: ``` [1/3] 解析文档信息... → token=bascnxxx, doc_type=bitable [2/3] 添加权限... → 调用 API 返回错误码 99991661(成员已存在) [3/3] 幂等处理... → 视为成功,无需重复添加 ``` **Agent 回复**: ``` ✅ 权限已存在! 📄 文档:bascnxxx 🔗 链接:https://xxx.feishu.cn/base/bascnxxx 👤 权限:完整权限 (full_access) 你已经有这个文档的完整权限了。 ``` --- ## 配置引导流程 🔧 > 当第一步检查发现配置缺失时,按以下流程引导用户配置。 ### A. 获取 App ID 和 App Secret ``` 📱 获取飞书应用凭证: 1. 打开浏览器,访问:https://open.feishu.cn/app 2. 登录你的飞书账号 3. 点击「创建企业自建应用」或选择已有应用 4. 在左侧菜单找到「凭证与基础信息」 5. 复制以下内容: - App ID(cli_ 开头的字符串) - App Secret(点击「查看」后显示) 请把 App ID 和 App Secret 发给我,格式如下: appId: cli_xxxxxxxx appSecret: xxxxxxxx ``` ### B. 获取 ownerOpenId **优先从会话上下文提取**:若上下文中出现 `user:ou_xxx` 格式,直接提取 `ou_xxx` 使用。 **否则引导用户获取**: 1. 登录 [API 调试台](https://open.feishu.cn/api-explorer),找到发送消息接口 2. 在「查询参数」页签,将 `user_id_type` 设置为 `open_id` 3. 点击「快速复制 open_id」 详见:https://open.feishu.cn/document/faq/trouble-shooting/how-to-obtain-openid **用户回复后**: 1. 验证格式是否正确(以 `ou_` 开头) 2. 在当前会话中使用此 ownerOpenId ### C. 配置应用权限 ``` ⚠️ 在使用前,还需要给应用添加权限: 1. 在飞书开放平台,点击左侧「权限管理」 2. 搜索并开通以下权限: - docs:permission.member:create (添加云文档协作者) 3. 点击「发布版本」使权限生效 如果权限显示「待确认」,需要联系企业管理员审批。 ``` --- ## 权限级别说明 🔐 | 权限值 | 中文名 | 能做什么 | 适用场景 | |--------|--------|----------|----------| | `view` | 只读 | 只能查看,不能修改 | 分享给他人查看 | | `edit` | 可编辑 | 可以修改内容,不能管理权限 | 协作编辑 | | `full_access` | 完整权限 | 可以编辑、管理权限、删除 | 文档所有者(推荐) | > 💡 建议:给用户添加 `full_access` 权限,这样用户可以完全控制文档。 **权限选择建议**: | 场景 | 推荐权限 | 原因 | |------|----------|------| | 用户自己的文档 | `full_access` | 完全控制 | | 协作编辑 | `edit` | 避免误删 | | 只读分享 | `view` | 安全最小化 | > 💡 默认使用 `full_access`,但可在执行时询问用户需求。 --- ## 错误处理大全 ⚠️ | 错误码 | 错误信息 | 原因 | 解决方案 | 处理动作 | |--------|---------|------|----------|----------| | `10003` | app id or app secret is invalid | App ID 或 App Secret 错误 | 检查配置,确保复制正确 | 重新配置后重试 | | `99991661` | 成员已存在 | 用户已有权限 | 视为成功,无需处理 | 直接返回成功 | | `99991663` | Invalid access token | token 过期或无效 | 重新获取 tenant_access_token | 重新执行 2.2 | | `99991664` | Permission denied | 应用没有权限 | 引导配置应用权限 | 跳转配置引导 C | | `99991600` | token not found | 文档 token 不存在 | 检查 file_token 是否正确 | 确认后重试 | --- ## 最佳实践 💡 ### 配置管理 - ✅ 首次使用时引导用户配置 - ✅ 配置保存后,后续自动读取 - ⚠️ 不要在日志中输出 App Secret ### 错误处理 - ✅ 每一步都要检查返回的 code - ✅ 失败时给出清晰的错误原因 - ✅ 提供具体的解决方案和处理动作 ### 用户体验 - ✅ 每步输出进度提示 `[1/4] [2/4] [3/4] [4/4]` - ✅ 成功后返回文档链接 - ✅ 告诉用户权限已添加 - ✅ 提示用户可以直接访问 - ✅ 成功后询问用户是否需要将 ownerOpenId 写入配置文件 ### 安全考虑 - ⚠️ App Secret 不要硬编码在 skill 中 - ⚠️ 不要在回复中显示完整的 App Secret(只显示前4位 + `***`) - ⚠️ token 有效期约 2 小时,建议缓存避免频繁请求 **敏感信息脱敏**: | 信息类型 | 原始值 | 脱敏后 | |---------|--------|--------| | App Secret | `abc123xyz789` | `abc1***` | | tenant_access_token | `t-xxx123456` | `t-xxx***` | | ownerOpenId | `ou_abc123` | `ou_abc***` | **脱敏实现**: ```python def mask_secret(s, show=4): return s[:show] + '***' if len(s) > show else '***' ``` --- ## 相关链接 📎 | 资源 | 链接 | |------|------| | 飞书开放平台 | https://open.feishu.cn/app | | 权限配置指南 | https://open.feishu.cn/document/docs/permission/permission-member/batch_create | | 获取 Open ID | https://open.feishu.cn/document/faq/trouble-shooting/how-to-obtain-openid | --- ## 快速参考卡片 📌 ``` ┌─────────────────────────────────────────────────────────┐ │ 飞书权限添加快速参考 │ ├─────────────────────────────────────────────────────────┤ │ 1. 检查配置:~/.openclaw/openclaw.json │ │ - appId (必需) │ │ - appSecret (必需) │ │ - ownerOpenId (可选,会话上下文补充) │ │ - 应用权限: docs:permission.member:create (必需) │ ├─────────────────────────────────────────────────────────┤ │ 2. 获取 tenant_access_token: │ │ POST /auth/v3/tenant_access_token/internal │ │ Body: {app_id, app_secret} │ ├─────────────────────────────────────────────────────────┤ │ 3. 获取云文档 token: │ │ 创建时返回 或 从 URL 解析 │ │ 自动识别 doc_type: /base/→bitable, /docx/→docx... │ ├─────────────────────────────────────────────────────────┤ │ 4. 添加权限: │ │ POST /drive/v1/permissions/{token}/members │ │ Header: Authorization: Bearer {token} │ │ Body: {members: [{member_type, member_id, perm}]} │ ├─────────────────────────────────────────────────────────┤ │ 文档类型: │ │ bitable | docx | doc | sheet | folder | file | wiki │ │ 权限级别:view | edit | full_access │ └─────────────────────────────────────────────────────────┘ ```