为 AI 知识库设计 31 项权限的 RBAC
Simmetric Chat 的基于角色的访问控制如何用 31 项权限和 13 个菜单部分保护工作区、项目和审计线索。
为什么 AI 知识库需要真正的访问控制
AI 工作区集中了你最敏感的操作知识:内部文档、带 RAG 引用的聊天记录、代理配置以及到外部系统的连接。当这个表面向整个公司开放时,"谁能看到什么"就不再是一个锦上添花的功能请求,而是变成了与数据库权限同类的问题——一个必须在构造上就正确的设计决策。
Simmetric Chat 正是这样处理的。每个经过身份验证的请求在触及业务数据之前都要经过角色和权限检查,而保护聊天记录的同一种模型也决定了用户能在侧边栏中看到应用的哪些部分。本文介绍系统的设计方式:覆盖平台资源表面的 31 项权限、将这些权限映射到用户界面的 13 个菜单部分,以及阻止已认证用户访问不属于他们的记录的请求级守卫。
权限模型:31 项细粒度权限
模型的核心是固定词汇表,包含 31 项权限。每项权限命名一个资源和一种操作,遵循 resource:action 约定。工作区、项目、聊天和文档各携带完整的读/写/删三元组,因为这些是用户在日常工作中创建和销毁的资源:
workspace:read、workspace:write、workspace:deleteproject:read、project:write、project:deletechat:read、chat:write、chat:deletedocument:read、document:write、document:delete
围绕这个核心的是创建流程本身的权限(workspace:create、project:create)、平台管理权限(admin:users、admin:settings、admin:roles)以及读取或配置 LLM 提供商的权限(provider:read、provider:write)。存档与核心资源一样获得三元组处理,因为归档的对话仍然是敏感数据。
一组六项备份权限将目标管理、任务执行、日志检查和恢复操作分开——这种划分很重要,因为"可以触发备份"和"可以将生产数据恢复到任意工作区"是不同级别的信任。最后,memory:read 和 memory:write 覆盖每用户、每工作区的记忆系统,filters:manage 将过滤器管理限制为仅管理员。
权限作为数据库中的枚举表存储并按名称引用。自定义角色通过从 31 项权限集中选择来组装,因此操作员可以表达"档案管理员"或"只读分析师"而无需接触代码:
{
"name": "archivist",
"permissions": ["workspace:read", "document:read", "archive:read", "chat:read"]
}出厂时附带两个默认角色。管理员角色持有全部 31 项权限;用户角色持有一个工作子集——对工作区和提供商的读取访问、对聊天和文档的读写、对存档的读取、对工作区和项目的创建权限,以及对自己记忆的完全管理。两个角色在应用程序逻辑中都没有特殊处理;它们都是权限中间件像解析其他任何行一样解析的普通行。
菜单部分:塑造界面的权限
只保护 API 路由的访问控制会产生令人困惑的体验——用户点击失败的按钮。因此 Simmetric Chat 还将权限映射到控制侧边栏可见性的 13 个菜单部分。这些部分是应用的结构解剖:
dashboard、chat、documents、knowledgeBase、workspaces、projects、marketplace、mcpConnections、eventLog、analytics、widget、settings 和 uploads。
每个角色携带自己的菜单部分列表,以字符串存储,这样无需数据库迁移即可添加新部分。用户角色可能看到 dashboard、chat、documents、knowledgeBase、workspaces、widget 和 uploads,而管理员角色看到全部 13 个。结果是界面本身反映了角色能做什么:没有 analytics 权限的用户永远不会遇到可点击的 analytics 入口。
权限检查和菜单可见性是同一个底层角色的两种表达,这意味着在审计期间有单一事实来源可以推理。
请求级守卫:RBAC 作为中间件
每个 API 请求解析用户及其角色和权限(带缓存),并将解析后的身份附加到请求上。在此之上是四个中间件守卫,各自回答不同的问题:
requirePermission——管理员始终通过;其他人必须持有路由列出的每项权限。未经身份验证的请求获得401;权限不足的已认证用户获得403并附明确的 "Insufficient permissions" 错误。requireAdmin——管理路由的硬性门禁,对非管理员返回403"Admin access required"。requireProjectAccess——针对项目所有权和显式访问行的 IDOR 检查。requireWorkspaceAccess——针对工作区的同类检查,接受工作区所有权、父项目所有权或显式访问授权。
最后两个值得强调,因为它们处理困扰多租户系统的漏洞类别。IDOR(不安全的直接对象引用)攻击发生在 /api/workspaces/123 更信任 URL 中的标识符而非调用者身份时。已认证——但未获授权访问工作区 123——的用户绝不能通过猜测标识符来读取其文档。Simmetric Chat 对这类请求在用户未认证时返回 401,在用户仅缺乏访问权时返回 403 "Insufficient permissions",而不是泄露资源的存在或内容。
路由保护是声明式的。工作区 CRUD 需要 requireWorkspaceAccess;创建工作区需要 workspace:create 权限并遵守计划限制;角色管理位于 requireAdmin 之后。路由表读起来就像安全策略,这正是当新工程师问"这个端点能做什么?"时你想要的属性。
审计线索:知道谁做了什么
权限检查回答"这个操作应该被允许吗?";审计线索回答"实际发生了什么?"。Simmetric Chat 在可浏览的事件日志中记录重要平台操作的审计线索——身份验证事件、文档操作、设置更改和管理操作。
这种结合让 RBAC 从理论变为可操作。当发生意外的文档删除时,事件日志识别行为者和操作;权限模型解释哪个角色允许了它;调整角色的权限或其菜单部分即可关闭缺口。审计表面本身通过 eventLog 菜单部分进行权限门控,因此与安全相关的活动记录只对获信任的角色可见。
敏感的保留更改——例如配置聊天消息保留天数——本身也会被审计,因此即使控制数据生命周期的控件也会留下自己的痕迹。
这在实践中是什么样子
考虑一个三角色部署。管理员保留完整的 31 项权限集和全部 13 个菜单部分。日常用户角色在聊天、文档和自己拥有的工作区内工作,永远不会看到事件日志或提供商设置。合规审计员获得文档、聊天和存档的只读权限,外加事件日志访问权——能够检查任何内容,更改任何内容都不行。
这些都不需要分叉应用或编写自定义中间件。它需要将权限组装成角色并映射菜单部分。这就是 31 项权限模型所服务的设计目标:粒度足够细,能表达真实的组织边界;足够简单,政策能装进头脑。
要查看完整的权限词汇表和角色管理端点,请阅读 API 参考。要在管理界面中动手了解角色、权限和菜单部分,请参阅 使用指南。
