KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
配套项目 · 权限与多租户最小可运行实现 — keel 龙骨
权限与多租户:从若依模型到注解式鉴权 的配套项目:配套项目 · 权限与多租户最小可运行实现
这门课的每个结论都在这个项目里跑过。它不追求框架完整,只保证判定内核只有一份,
并且能被真实 HTTP 请求验证。
文件
| 文件 | 作用 | 对应章节 |
|---|---|---|
schema.sql |
15 张表:租户/组织/账号/成员/工作空间/权限点/菜单/角色/ACL | 01、02、06 |
db.py |
SQLite 连接与建表(刻意不用 ORM,SQL 原文更好读) | — |
errors.py |
拒绝原因也结构化(403 / 404 分开) | 05 |
identity.py |
身份上下文:user → member → 租户内身份,ContextVar 传递 |
03 |
rbac.py |
角色 → 权限点 → 数据范围(菜单 / 接口 / 数据三层) | 02、04 |
acl.py |
资源级 ACL,带权重(use<observe<edit<manage) | 06 |
guards.py |
三种落地形态:函数内判定 / 依赖注入 / 装饰器 | 02、03 |
api.py |
FastAPI 接线,真实 HTTP 验证 | 03 |
seed.py |
演示数据:两个租户,同一人在两边角色不同 | 01 |
demo.py |
跑一遍全部判定,打印正文引用的输出 | 全部 |
test_auth.py |
14 条 pytest,每条都是一次「主动破坏」 | 全部 |
api_probe.py |
对 api.py 打 10 个真实请求,打印状态码 |
03、05 |
跑起来
# 1) 全流程演示(正文里的输出片段都来自这里)
python demo.py
# 2) 判定内核的测试
python -m pytest test_auth.py -q # 14 passed
# 3) 真实 HTTP 验证(需要 fastapi + httpx)
python api_probe.py
三处值得注意的实现选择
- 租户 id 永远由服务端认定:客户端传的
X-Tenant-Id只是"选择哪个上下文",
验证权在member表(identity.resolve_identity)。所以伪造它只会得到403 not_a_member_of_tenant,不会让你变成另一个租户的人。 - 不存在与无权返回同一个 404:跨租户 id 和真不存在的 id 走同一条分支
(acl.load_resource),避免用状态码探测别人的资源 id。 - 身份放 ContextVar,依赖与端点都必须
async def:FastAPI 会把同步的依赖
和端点丢进线程池,而 ContextVar 不跨线程池传递。这条在开发时真的踩了两次
(端点同步 → 依赖同步),正文 02 章有完整记录。