当你的 Agent 能操作多个系统、多种资源时,谁能做什么、谁不能做什么,就不再是细节,而是安全边界。今天我们用 RBAC 把权限控制从"散落检查"升级为"可维护的策略"。
if user == "admin" ?引导问题:
if user.Department == "HR",6个月后新来一个功能,你还记得要在哪里加检查吗?答案揭示:
"散落检查"(Ad-hoc checks)的问题:
RBAC(Role-Based Access Control)的优势:
引导问题:
三元模型:
Policy 的核心问题:can(user, action, resource) → bool
用表格思考:
| Role | search_kb | create_ticket | read_user_info | approve_ticket | manage_roles |
|---|---|---|---|---|---|
| employee | ✅ | ❌ | ❌ | ❌ | ❌ |
| l1_support | ✅ | ✅ | ❌ | ❌ | ❌ |
| l2_support | ✅ | ✅ | ❌ | ✅ | ❌ |
| hr | ✅ | ❌ | ✅ | ❌ | ❌ |
| admin | ✅ | ✅ | ✅ | ✅ | ✅ |
引导问题:
admin 能不能用"继承"来代替把所有权限都列出来?(角色继承)在路由中使用:
| 概念 | 说明 | 在哪里用 |
|---|---|---|
| Permission | action:resource 的最小权限单元 |
注册在 Role 上 |
| Role | 一组 Permission 的集合,可继承 | 赋给 User |
| Policy Check | can(user, action, resource) |
Tool 执行前、Handler 前 |
| Tool Registry | 工具声明所需权限,执行前自动检查 | Agent 调用工具时 |
| Secure Retriever | 搜索结果按用户权限过滤 | RAG 返回 chunks 时 |
| RBAC Middleware | HTTP 层自动拦截越权请求 | 路由注册时 |
角色继承的好处:
admin 不需要手动列所有权限,通过继承自动获得。
运行前,问自己:
can(user, action, resource) 的完整执行路径是什么?(从 HTTP 请求到 DB 查角色到权限匹配)PermissionDeniedError 为什么要定义成独立类型而不是 errors.New?internal/rbac/ 目录下的完整实现go test ./internal/rbac/...contractor:只能搜索 public 分类的 chunksExecuteTool 在权限不足时返回清晰的错误信息GetAvailableTools 为不同用户返回不同的工具列表/api/chat handler 中,根据当前用户动态构建 LLM 的工具列表SecureRetrieverpublic chunks,hr 额外看到 confidential chunksQ: 用户的角色应该存在 JWT 里还是每次查数据库?
A: 两者各有取舍:
建议:用 Redis 缓存用户角色(TTL 5分钟),兼顾性能和实时性:
Q: GetAvailableTools 要不要把没权限的工具完全隐藏,还是返回但标记为 disabled?
A: 对 LLM 来说,隐藏比标记更好。因为:
Q: 权限矩阵应该硬编码还是存数据库?
A: 分层存储:
关联:RBAC 的角色继承本质上是一个有向无环图(DAG)。如果出现循环继承(A 继承 B,B 继承 A),系统会死循环。Course Schedule II 用拓扑排序检测是否有循环依赖。
与 RBAC 的对应:
关联:权限的传播路径。在复杂的角色继承树中,某个权限从根角色传播到叶节点需要经过多少跳?哪个角色是"权限瓶颈"?
复杂度:O(V²)(朴素),O((V+E)logV)(堆优化)
明天我们会:
准备问题: