飞书多维表格API权限配置指南:解决Python接入permission denied
做飞书多维数据表格自动化的同学,大概率都有过这种体验:Python 代码明明写得很顺,逻辑也简单,结果一跑就给我甩个
permission denied
,或者干脆返回一个“应用无权限”的提示。这时候你才会发现,真正花时间的不是调接口,而是把飞书那一堆权限配置理清楚。
这篇教程是系列的第二篇,上一篇已经把 Python 调飞书 API 读写多维表格的主流程走了一遍,这一篇我单独把“设置多维数据表格的权限”这件事拆开揉碎讲清楚。适合两种人看:一种是刚接触飞书开放平台、正准备从零接入的小白;另一种是代码已经写完、但一直被权限报错卡住的开发者。
1. 先搞明白:多维数据表格的权限到底卡在哪
飞书多维数据表格的权限,并不像我们平时理解的那样“勾一个开关就行了”。很多同学第一次接的时候,以为在开发者后台把
bitable
权限勾上,接口就能通,结果现实会给你上一课。
其实飞书开放平台的权限体系是分层的,至少包含下面几层:
- 应用层面的权限开关 :也就是 scope 权限,决定你这个应用能不能调用某个 API。
- 文档层面的协作者授权 :多维表格本身是文档,你得把应用机器人加进文档的协作者列表里,否则就算应用有权限开关,它也进不去那张表。
-
用户身份与租户身份的区别
:你用
tenant_access_token调接口,代表的是应用所在企业;你用user_access_token调接口,代表的是某个具体用户。两者能访问的数据范围完全不一样。 - 版本发布与审核 :你改了权限之后,必须发布新版本,企业管理员审核通过之后,新的权限才会真正生效。
我习惯用一个类比来解释这几层关系:你的应用是一个访客,
scope
权限就是它的“门禁卡”,告诉这套系统它能进入哪些大门;而文档授权是“业主开门”,即使访客有了门禁卡,业主不让他进房间,他依然只能站在门外。把这层关系想明白,后面遇到的绝大多数权限问题都能定位。
所以如果你勾了权限还是报错,先不要怀疑代码,按照这个顺序排查:应用是否发布了新版本、表格文档是否把应用机器人加为了协作者、当前用的 token 身份是否是预期身份。
1.1 权限体系分层速览
为了方便对照,我把层级和关键检查点整理成了一张表:
| 层级 | 作用对象 | 关键配置 | 容易忽略的点 |
|---|---|---|---|
| 应用 scope 权限 | 开放平台应用 | 在权限管理中勾选对应 API 权限 | 勾选后必须发布新版本 |
| 文档协作者授权 | 多维表格文档 | 把应用机器人添加到文档成员中 | 只给表格链接但未授权,仍然报无权限 |
| Token 身份 | 请求凭证 | 选择 tenant 还是 user token | 两个 token 看到的范围差异很大 |
| 云空间权限 | 多维表格所在目录 | 确认所在文件夹对应用可见 | 云空间限制也会导致表格不可读 |
| 管理员审核 | 企业后台 | 发布版本后需审核通过 | 部分企业开启了强制审核,需人工通过 |
这五个层级,任何一个有问题,你在 Python 端收到的报错可能都差不多。所以我在遇到权限问题时,基本都是按这个表从上往下一个个对。
1.2 为什么已经勾选了权限还是报错
这是我在各种技术群里看到出现频率最高的问题。明明后台权限已经勾上了,为什么还报
94010000
类似这样的权限错误?
答案通常落在两个地方。
第一个是 没有发布新版本 。飞书的权限配置并不是“保存即生效”,你勾选权限之后,还需要创建一个应用版本并发布。如果企业开启了管理员审核,还得等管理员通过。在这个流程走完之前,应用真正运行时使用的还是旧版本的权限配置。
第二个是 表格文档没有授权给应用 。我一开始也在这里栽过跟头,当时以为权限开关开了就万事大吉,结果用 Python 反复请求都是 403。后来才发现,得多维表格文档右上角的分享按钮里,把“应用机器人”添加为协作者,并且给“可编辑”权限。这一步不做,应用连读取表格元数据都会失败。
2. 创建自建应用并拿到凭证
在配置任何权限之前,你首先得有一个应用。飞书开放平台的企业自建应用,相当于给你的自动化脚本发了一个身份凭证。这个身份凭证由
App ID
和
App Secret
共同组成,后面获取访问令牌全靠它。
2.1 进入开发者后台并创建应用
打开飞书开放平台,登录你的企业管理后台账号,在“开发者后台”里选择“企业自建应用”,点击创建应用。名称可以随便起,比如“多维表助手”,图标可以先用默认的,后面再换。
有一点提示:创建一个应用时选择的“可用范围”会影响谁能使用这个应用。如果你只是自己调试,选择“仅部分成员”并把你自己加进去就够了。如果选成“全体成员”,流程上不会有错,但在企业场景下容易牵扯到不必要的审批流程。
创建完成之后,进入应用详情页,你会看到左侧有一排菜单。这里我建议先把两样东西记下来:
-
App ID
:应用的唯一标识,形如
cli_xxxxxxxxxxxx。 - App Secret :应用的密钥,形如一串随机字符串。
这两个值后面在 Python 代码里要用到,建议直接存到环境变量或者本地配置文件中,不要硬编码在代码里提交到仓库,不然哪天代码泄露,整个应用的凭证就全完蛋了。
2.2 拿到凭证后先做一次连通性测试
拿到凭证之后,不要急着去写业务逻辑。先用最简短的代码验证一下能不能通过接口获取到访问令牌,这个步骤能帮你把“网络问题”“参数错误”“凭证失效”这些基础问题提前挡在门外。
我一般会直接用
requests
库来测:
import requests
url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
payload = {
"app_id": "cli_xxxxxxxxxxxx",
"app_secret": "你的_app_secret"
}
resp = requests.post(url, json=payload)
print(resp.json())
如果返回结果里有
"code": 0
和
"tenant_access_token"
,说明凭证没问题;如果返回
"code": 10003
之类的错误码,说明 App ID 或 App Secret 不对,回开发者后台重新核对一下。
这一步很重要,因为后面所有 API 调用都要带着这个 token 走,如果 token 都拿不到,后面配置再多权限也白搭。
3. 按最小权限原则配置多维数据表格权限
飞书开放平台对多维数据表格开放的 API 权限,在权限管理页面里通常以
bitable
开头。打开应用的“权限管理”页面,搜索“多维数据表格”或者“bitable”,会看到一列权限开关。这里我建议遵循最小权限原则:只需要“读取”就只开读权限,需要“写入”再开读写权限,不要图省事把权限全勾上。
3.1 常见 bitable 权限范围和适用场景
| 权限标识 | 权限能力 | 适用场景 |
|---|---|---|
| bitable:app | 查看、创建、编辑多维数据表格 | 常用,适合读写表格和记录 |
| bitable:app:readonly | 只读访问多维数据表格 | 只做数据查询和分析 |
| bitable:app:manage | 管理多维数据表格 | 需要创建新表、删除表时使用 |
| bitable:app:write | 写入多维数据表格记录 | 只做数据写入时可以单独选 |
我自己在做数据同步脚本的时候,通常只开
bitable:app
,这个权限能覆盖查看表格元数据、读取记录、新增记录、更新记录这几类常规操作,既省事又不会引入多余的权限风险。
如果只是写个定时任务,把某个外部系统的数据推送到飞书表格里,那其实
bitable:app:write
就够了,连读权限都不用开。
3.2 发布版本并等待权限生效
勾选权限之后,页面右上角会提示你“创建版本并发布”。这一步新手容易忽略,觉得权限开好了就能用了。实际上飞书的权限体系会在运行时校验应用版本,你必须:
-
在“版本管理与发布”页面填写版本号,比如
1.0.0。 - 填写版本说明,比如“开通多维表格读写权限”。
- 点击“申请发布”,提交给企业管理员审核。
如果企业后台没有设置强制审核,发布后会立即生效;如果有管理员审核流程,你需要去企业管理后台帮自己通过一下,或者在群里喊管理员放行。
这里有个经验供参考:在开发调试阶段,我会把应用可用范围设置成仅自己,并且选择无需管理员审核的发布模式;等到代码稳定、需要给业务团队用的时候,再申请正式发布并走审核流程。这样开发效率会高很多。
3.3 把表格文档授权给应用,这是最关键的一步
这一步在整个教程里最容易踩坑,也是我见过最多人翻车的地方。
打开你要操作的那张多维数据表格,在页面右上角点击“分享”按钮。弹窗里除了可以添加成员,还有一个搜索框可以搜索“应用”。你需要搜索你刚刚创建的那个应用的名称,比如“多维表助手”,然后把它添加为协作者。
添加的时候,角色一定要选“可编辑”。如果你只给了“可阅读”,那么 Python 端执行写入操作时会被拒绝;如果你想做的是数据查询,那给“可阅读”也够用。
还有一种情况是表格嵌在云空间文件夹里,文件夹本身对应用不可见。这种问题通常表现为:应用有权限、文档也分享给应用了,但 API 返回“文档不存在”。如果遇到这种情况,需要检查一下这张表所在的云空间或者文件夹是否也对该应用可见。
做完文档分享这一步,我再强调一下: 这一步和 scope 权限缺一不可 。只有 scope 没有文档授权,接口报无权限;只有文档授权没有 scope,接口同样报无权限。两者是“与”的关系,不是“或”的关系。
4. Python 端接入代码解析与验证
配置完权限之后,你终于可以回到 Python 这边做真正的验证了。我这里提供一个完整的最小示例逻辑:获取 token → 读取表格 → 往表格加记录。
4.1 获取 tenant_access_token 的标准写法
在飞书 API 体系中,
tenant_access_token
代表“企业自建应用身份”。也就是说,你的脚本以应用的身份去操作表格,而不是以某个员工的个人身份。很多后台自动化的场景都用它,因为它不依赖某个用户是否在线。
获取 token 的接口路径是固定的,值得注意的坑是:token 有有效期,通常是 2 小时,建议在代码里把 token 缓存下来,快过期时再重新获取。频繁获取 token 不仅没有意义,还容易触发频控。
import requests
import time
APP_ID = "cli_xxxxxxxxxxxx"
APP_SECRET = "你的_app_secret"
cache = {}
def get_tenant_access_token():
now = time.time()
if cache.get("expire_at") and now < cache["expire_at"]:
return cache["token"]
resp = requests.post(
"https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
json={"app_id": APP_ID, "app_secret": APP_SECRET},
timeout=10,
)
data = resp.json()
if data.get("code") != 0:
raise RuntimeError(f"获取 token 失败: {data}")
cache["token"] = data["tenant_access_token"]
cache["expire_at"] = time.time() + data["expire"] - 60
return cache["token"]
这段代码里减掉的 60 秒是保险机制,防止 token 刚到手就过期。实际项目中可以直接用一个全局变量保存,没必要引额外的缓存库。
4.2 用代码读取多维数据表格的表信息和记录
拿到 token 之后,读取表格的第一步是拿到表格的
app_token
。
app_token
就是多维表格文档的识别标识,一般在多维表格的链接里就能看到。比如链接长这样
https://xxx.feishu.cn/base/xxxxx
,那一串
xxxxx
就是
app_token
。
我们还不知道表 ID 时,可以调用接口获取表格下有哪些数据表:
def list_tables(app_token):
token = get_tenant_access_token()
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json; charset=utf-8",
}
resp = requests.get(url, headers=headers, timeout=10)
return resp.json()
如果返回的
code
是 0,并且
data.items
里有数据,那就说明你已经拿到了数据表列表。这个接口非常能检验前面那些权限配置是否正确,因为如果你漏了文档分享授权,这一步就会报权限错误。
获取到
table_id
之后,再调用记录查询接口来读取表格里的具体行数据:
def list_records(app_token, table_id):
token = get_tenant_access_token()
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records"
headers = {"Authorization": f"Bearer {token}"}
resp = requests.get(url, headers=headers, timeout=10)
return resp.json()
响应里的
data.items
就是多行记录,每条记录的字段名对应多维表格里的列名。不过要提醒一句:飞书把字段值封装得比较深,日期、人员、附件这类类型返回的数据结构和纯文本不一样。排查数据格式的时候,建议先拿一条记录打印出来看看。
4.3 用代码往表格写入数据
读取没问题之后,再来验证写入。写入记录用的是 POST 请求,注意传参格式是
records
列表,每个元素是一个
fields
字典,字段名必须和多维表格里的列名完全一致。
def add_records(app_token, table_id, rows):
token = get_tenant_access_token()
url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_create"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json; charset=utf-8",
}
payload = {"records": [{"fields": row} for row in rows]}
resp = requests.post(url, headers=headers, json=payload, timeout=10)
return resp.json()
调用时这样传参:
rows = [
{"姓名": "张三", "状态": "已完成"},
{"姓名": "李四", "状态": "待处理"},
]
result = add_records("你的_app_token", "你的_table_id", rows)
print(result)
如果返回结果里
code
是 0,说明写入成功。这里有个非常常见的问题:字段名和表格里的列名不完全一致,比如多了个空格或者用了别名,就会出现“字段不存在”之类的报错。建议在调试阶段先把表格表头截图或者复制出来,照着写字段名。
另外,批量创建接口单次最多支持的记录数有限,一次传几百行很容易触发限流。我通常每次控制在 100 条以内,分批写入,中间加个
time.sleep(0.5)
,这样既稳定又不容易被频控封禁。
5. 常见问题与权限排查实战技巧
既然这篇文章的重点是权限,那这一部分我就集中写权限相关的报错和排查经验。下面这些都是我在真实项目里遇到过、也帮别人排查过的问题,整理出来给你当速查表。
5.1 高频报错速查表
| 报错信息或现象 | 大概率原因 | 解决方向 |
|---|---|---|
permission denied
/ 权限不足
| scope 未勾选或版本未发布 | 回权限管理重新勾选,发布新版本 |
app not found
/ 应用不存在
| App ID 填错或应用被停用 | 核对凭证,确认应用状态 |
document not found
| 表格未授权给应用,或云空间不可见 | 检查文档分享,检查云空间目录 |
写入时报
field not found
| 字段名和表格列名不一致 | 复制表头核对字段名 |
返回
code: 99991
等频控码
| 请求频率过高 | 减少单次批处理量,加延时 |
| 读取人员字段为空 | 权限不足读取部分字段类型 | 确认人员字段是否需要单独开权限 |
| 版本发布后仍然报旧权限错误 | 发布流程未走完或管理员未审核 | 后台确认发布状态和审核状态 |
| 使用 user_access_token 才能访问 | 该表格对应用机器人的授权丢失 | 重新通过文档分享添加应用为协作者 |
这张表不敢说覆盖所有情况,但覆盖了 80% 的新手报错。
5.2 一套亲测有效的排查顺序
我遇到权限问题时的排查顺序,基本是下面这样的,按照这个顺序走,很少会白折腾:
- 先确认 token 能不能拿到 。如果 tenant_access_token 获取失败,直接查凭证和网络,不用看后面的权限。
- 再确认 app_token 和 table_id 是否正确 。很多“无权限”其实只是资源标识写错了。
- 用开发者后台的“接口调试”工具直接试一次 。飞书开放平台提供了在线调试能力,你可以在里面用当前应用的 token 直接调接口。如果在线调试能通,你的权限配置就是没问题的;如果在线调试都不通,那问题出在应用配置上,和 Python 无关。
- 检查文档分享 。确认应用机器人已经加到多维表格协作者里,而且角色是“可编辑”。
- 检查版本发布状态 。确认最新版本已经发布,并且审核通过。
- 最后才怀疑代码 。代码层面的问题通常不是权限,而是字段名、请求格式或者参数拼写。
这套顺序帮我节省了大量时间。如果你自己排查没有头绪,建议也按这个顺序来,别一上来就在代码里打日志,那样往往越查越乱。
6. 最后分享几个实在的经验
写到这里,这篇教程的主体内容基本讲完了。关于权限配置这件事,我还想从个人经验角度补充几点:
第一, 权限配置永远比代码更容易出错 。很多同学一遇到报错就怀疑是不是 requests 写法不对,实际上飞书 API 的接口封装很规范,反倒是权限这种“看不见摸不着”的配置,出了问题最难定位。所以我的习惯是,每次新写一个自动化脚本,先花十分钟把权限检查一遍,再开始写代码。
第二, 调试阶段尽量用最小权限 。只开当前功能需要的权限,不要想着“反正都接了,干脆全开”。权限越多,版本审核时管理员越容易卡你,后续如果应用被安全审计,全量权限也是减分项。按最小权限来,对谁都有好处。
第三, token 缓存一定要做 。我看到很多教程里没有提这一点,但实际项目里如果没有 token 缓存,脚本每次运行都要重新获取 token,一方面慢,另一方面容易被限流。这篇文章里的示例已经写了缓存逻辑,你可以直接参考。
第四, 线上出问题先看版本状态,别看代码 。我自己有一次改了权限配置,本地怎么调都通,一发到线上就报权限错误。后来才发现线上跑的应用版本没更新。从那以后,我每次改完权限,都会先确认目标环境里应用的实际版本号。
多维数据表格的权限配置,说到底就是两个词:一个是“授权”,一个是“发布”。把这两个词牢记在心里,再配合上面的排查顺序,飞书 API 调用这条路基本就通畅了。下一篇教程,我会继续写如何对表格里的数据进行复杂的筛选和更新,包括如何用 Python 实现增量同步、如何批量更新已有记录,如果你正在做类似的事情,到时候可以接着看。
更多推荐

所有评论(0)