
Baserow 企业版 RBAC 权限系统技术指南角色、团队与作用域详解【免费下载链接】baserowBuild databases, automations, apps agents with AI — no code. Open source platform available on cloud and self-hosted. GDPR, HIPAA, SOC 2 compliant. Best Airtable alternative.项目地址: https://gitcode.com/GitHub_Trending/ba/baserow本篇技术指南面向希望深入理解 Baserow 企业版基于角色的访问控制Role Based Access ControlRBAC内部原理的开发者。文章以 enterprise/docs/RBAC-guide.md 为主体骨架结合仓库内 RBAC 模块的源码、模型与测试实现系统讲解 RBAC 的术语体系、默认角色、作用域继承规则、角色判定优先级、数据模型以及权限分配与校验的底层调用链帮助读者掌握在企业级权限架构中正确使用与二次开发 RBAC 的能力。前置知识Baserow 权限系统基础RBAC 是 Baserow 权限系统Permission System之上的一层具体实现。在阅读本文之前建议先阅读 docs/technical/permissions-guide.md以理解如下核心概念ObjectBaserow 中的任意数据对象如 Field、Row、Table、Database、Workspace、User、Team、Role、Webhook 等。对象之间存在父子层级关系例如Table是Database的子对象。Actor可以执行操作的主体可以是User、Personal API Token甚至AnonymousUser。OperationActor 对 Object 执行的动作例如database.list_tables列出某 Database 下的 Tables、database_table.create_row在某 Table 中创建 Row。ContextOperation 所作用的对象实例。Permission request由Actor, Operation, Context组成的三元组是权限系统判定的基本单位。Permission manager权限系统中可插拔的判定组件每个 Permission manager 可以对请求做出允许Allow、拒绝Disallow或放行Passthrough三种决定。Baserow 按固定顺序依次让各 manager 处理请求若全部放行则默认拒绝。Subject包含所有 Actor也包含 Actor 的集合如 Teams。Workspace操作发生的空间范围旧称 Group。权限系统在设计上刻意保持可扩展性官方文档明确以支持 enterprise 目录中的 RBAC为约束RBAC 正是通过注册一个新的PermissionManagerType即RolePermissionManagerType接入这一体系的。在默认设置中BasicPermissionManagerType只区分ADMIN与MEMBER两种角色角色名存储在WorkspaceUser.permissions字段中RBAC 则复用该字段作为 Workspace 级别的角色存储从而保证两种权限体系可以平滑切换、不产生数据重复或同步问题。这一点在RolePermissionManagerType的兼容逻辑中有直接体现。术语表RBAC 专属概念RBAC 在权限系统通用术语之上进一步定义了以下专属术语见 enterprise/docs/RBAC-guide.mdRole角色一组 Operation 的集合可以被赋予某个 Subject。当角色被赋予 Subject 后该 Subject 即获得该角色下全部 Operation 的权限。Custom Role自定义角色由 Actor通常是管理员创建的角色区别于 Baserow 默认内置的角色集合。从源码看Role模型带有workspace外键与default布尔字段见 enterprise/backend/src/baserow_enterprise/role/models.pydefaultTrue表示默认角色workspace非空则表示该角色属于某个 Workspace这正是自定义角色的数据基础。Team团队一组 Subject 记录的集合便于统一管理让高权限角色可以批量管理 Subject而无需逐个分配角色。一个 Team 仅关联一个 Workspace。Role assignment角色分配一个三元组表示在某个 Scope 上、将某个 Role 分配给某个 Subject。Scope作用域默认情况下一个 Role assignment 应用于 Workspace 的全部对象但角色的应用范围可以被限制到某个特定对象实例上这个对象实例即该角色的 Scope。此时该角色授予的权限只作用于这个对象及其全部子对象。Role assignment 的默认 Scope 是 Workspace对于Database应用额外允许的 Scope 还有Database和Table。从源码常量定义看见 enterprise/backend/src/baserow_enterprise/role/constants.py可分配角色的对象映射ROLE_ASSIGNABLE_OBJECT_MAP实际包含四级Scope 类型READ 操作UPDATE分配角色操作workspaceworkspace.read_roleworkspace.assign_roleapplicationapplication.read_roleapplication.update_roledatabase_tabledatabase.table.read_roledatabase.table.update_roledatabase_viewdatabase.table.view.read_roledatabase.table.view.update_role即在当前实现中Scope 除了文档提到的Workspace、Database、Table外还支持到View层级。主要原则角色、优先级与继承规则结构性角色与默认角色RBAC 中存在若干结构性角色与默认角色见 enterprise/backend/src/baserow_enterprise/role/default_roles.py它们以 UID 字符串标识NO_ROLE / NO_ACCESS移除给定 Scope及其所有子对象通过继承上的全部权限。在代码中该角色的 UID 常量为NO_ACCESS_ROLE_UID可通过 Django 设置NO_ACCESS_ROLE_UID覆盖默认NO_ACCESS见 constants.py。NO_ROLE_LOW_PRIORITY与 NO_ROLE 类似但如果某个 Team 在同一 Scope 上有角色则 Team 角色会被采纳。文档特别指出这一角色的存在主要是因为无法在 Group即 Workspace级别移除某个User的角色——Workspace 级别用户角色存储在WorkspaceUser.permissions字段中无法用无角色表达因此用低优先级占位符来区分。VIEWER只读操作集合。一个操作只有当它不修改数据库中的任何数据时才被认为是只读的。READ_ONLY这是源码中的一个隐藏角色hidden_roles不可被用户直接设置。当用户在某个子级作用域如 Table上拥有角色、但未拥有其祖先作用域如 Database的访问权限时系统会自动为其祖先补上READ_ONLY角色使中间对象可被看到以便访问子对象见 default_roles.py。除上述结构角色外默认存在以下角色每个默认角色都是前一个角色的超集见 default_roles.pyADMIN可对 Workspace 做任何事情包括权限管理workspace.assign_role、workspace.read_role、UpdateWorkspaceUserOperationType、团队与邀请管理等。BUILDER除权限管理外可以做任何事情包括建表、建视图、创建字段、Webhook、自动化、页面构建等。EDITOR可以在表中创建/更新/删除行。COMMENTER只能评论行。值得注意的实现细节默认角色在代码中按层级叠加构建——COMMENTER继承VIEWER的读写权限EDITOR继承COMMENTERBUILDER继承EDITORADMIN继承BUILDER。VIEWER又是在READ_ONLYNO_ACCESS基础上叠加而来。角色与操作之间通过Role.operations多对多关系关联见 models.py。角色判定规则当一个 Permission request 到来时系统按以下规则计算应使用的角色见 enterprise/docs/RBAC-guide.md最近祖先角色规则Rule of closest ancestor Role对某个 Context 上的操作取该 Context 最近祖先包含其自身上的 Role assignment无论它是 Team 角色还是 Actor 角色。Actor 角色优先规则Rule of Actor Role precedence在同一 Scope 上如果同时存在 Actor 自身的 Role assignment 和该 Actor 所属 Team 的 Role assignment则 Actor 角色总是优先于 Team 角色除非 Actor 角色是NO_ROLE_LOW_PRIORITY。Team 角色继承规则Rule of Team Roles inheritance如果某个 Scope 上不存在 Actor 角色或者 Actor 角色是NO_ROLE_LOW_PRIORITY则将该 Actor 所属全部 Team 的角色取并集即最宽松的 Team 角色生效。反向 Scope 继承规则Rule of reverse Scope inheritance当 Actor 在某个 Scope 上拥有至少一个VIEWER操作的角色分配时该 Scope 的全部祖先对象自动获得VIEWER角色——即使按照前面的规则它们应被赋予NO_ROLE。这使得 Actor 能够看到所有中间对象并访问子对象。这一自动角色在应用最近祖先角色规则时被忽略。对以上规则的简化概括层级优先Tables 角色 Database 角色 Workspace 角色主体优先Actor 角色 Team 角色NO_ROLE_LOW_PRIORITY⇒ 使用 Team A 角色 Team B 角色 …任意 n 级角色 ⇒ n-1 级 VIEWER 角色反向继承上述规则在 enterprise/backend/src/baserow_enterprise/role/handler.py 的get_computed_roles方法中有直接实现该方法遍历按层级排序的roles_per_scopes若某 Scope 包含当前 Context则保留该更精确的角色集合最近祖先规则若某子级 Scope 被 Context 包含且持有非 NO_ACCESS 角色则追加READ_ONLY角色反向继承并在代码注释中给出了对某个 Table 拥有 BUILDER 角色时其父 Database 必须可读的典型例子。实战示例规则如何组合生效以下示例均来自原文档结合上述规则逐一解读示例一仅 Actor 分配Actor A 的分配Workspace 1 上为 BUILDERTable 10Database 5 的子对象上为 VIEWER结果该 Actor 在除 Table 10 及其子对象外的所有地方是 BUILDER对 Table 10 及其子对象是 VIEWER最近祖先角色规则。示例二Actor 与 Team 在子级冲突Actor A 的分配Workspace 1 上为 BUILDERTable 10 上为 VIEWERActor A 属于 Team TTeam T 的分配Table 10 上为 COMMENTERTable 20同为 Database 5 子对象上为 NO_ROLE结果对 Table 10 及其子对象为 VIEWERActor 角色优先规则——Actor 的 VIEWER 压过 Team 的 COMMENTER对 Table 20 及其子对象为 NO_ROLE最近祖先角色规则其余地方为 BUILDER最近祖先角色规则。示例三多个 Team 取并集Actor A 的分配Workspace 1 上为 VIEWERActor A 属于 Team T1Table 10 上为 COMMENTER和 Team T2Table 10 上为 BUILDER。结果对 Table 10 及其子对象为 BUILDERTeam 角色继承规则——取最宽松者其余地方为 VIEWER最精确角色规则。示例四NO_ROLE 压制全部 Team 角色Actor A 的分配Workspace 1 上为 NO_ROLETeam T1Workspace 1 上为 COMMENTER、Team T2Workspace 1 上为 BUILDER。结果该 Actor 处处为 NO_ROLEActor 角色优先规则——NO_ROLE 是普通 Actor 角色直接生效。示例五NO_ROLE_LOW_PRIORITY 让位给 TeamActor A 的分配Workspace 1 上为 NO_ROLE_LOW_PRIORITYTeam T1Workspace 1 上为 COMMENTER、Team T2Workspace 1 上为 BUILDER。结果该 Actor 同时拥有 COMMENTER 与 BUILDER即处处为 BUILDERTeam 角色继承规则——NO_ROLE_LOW_PRIORITY 不生效取并集后最宽松者胜出。示例六反向 Scope 继承Actor A 的分配Workspace 1 上为 NO_ROLETable 10Database 5 的子对象上为 EDITOR结果对 Table 10 及其子对象为 EDITOR最近祖先角色规则对 Database 5、Application 5 和 Workspace 1 为 VIEWER反向 Scope 继承规则其余地方为 NO_ROLE最近祖先角色规则。技术细节RoleAssignment 数据模型要赋予某个 Actor 在给定 Scope 上的角色需要创建RoleAssignment。它是 RBAC 系统的核心对象权限请求所需的全部信息都存储在该对象中。数据模型如下原图见 enterprise/docs/RBACDataModel.jpg对应代码实现见 enterprise/backend/src/baserow_enterprise/role/models.pyRoleAssignment继承CreatedAndUpdatedOnMixin记录创建与更新时间。Subject通过一对 GenericForeignKeysubject_typesubject_id引用——因为 Subject 可以是不同类型的对象User、Team等。Scope同样通过 GenericForeignKeyscope_typescope_id引用——因为 Scope 可以是Workspace、ApplicationDatabase、Table、View等不同类型。role是Role的外键删除角色会级联删除相关分配。workspace指明该分配所属的 Workspace。模型层还定义了UniqueConstraint字段组合scope_id, scope_type, subject_id, subject_type保证同一 Subject 在同一 Scope 上最多只有一条分配记录。测试 enterprise/backend/tests/baserow_enterprise_tests/role/test_role_handler.py 验证了重复创建会抛出IntegrityError。Role模型本身见 models.py包含uid唯一标识符默认 UUID但默认角色使用ADMIN、BUILDER等固定 UIDname人类可读名称operations与Operation的多对多关系即该角色允许的操作列表default是否为默认角色hidden是否隐藏隐藏角色用户不可见、不可设置仅用于内部如READ_ONLY与FIELD_PERMISSION_EDITORworkspace可空的 Workspace 外键非空即自定义角色所属的 Workspace。从源码常量看FIELD_PERMISSION_EDITOR是一个特殊隐藏角色仅作为字段级RoleAssignment上的标记使用由字段权限管理器独占处理绝不会参与常规 RBAC 角色计算见 constants.py。分配角色的两种存储路径在 enterprise/backend/src/baserow_enterprise/role/handler.py 的assign_role方法中分配角色时根据条件走两条路径Workspace 级 User 主体直接设置WorkspaceUser.permissions属性为角色 UID。其中 BUILDER 会被翻译为MEMBER以保持与BasicPermissionManagerType的兼容其余角色直接写入 UID。这一步保证了RolePermissionManagerType与BasicPermissionManagerType之间的兼容切换不丢失也不重复存储信息。其他情况创建或update_or_create更新一条RoleAssignment记录然后发送role_assignment_created/role_assignment_updated信号。判断逻辑见is_workspace_level_assignmenthandler.py当scope workspace且 Subject 是User时为 Workspace 级分配。移除角色remove_role见 handler.py也遵循同样的分叉Workspace 级 User 则把WorkspaceUser.permissions置为NO_ACCESS_ROLE_UID否则删除对应的RoleAssignment记录并发送role_assignment_deleted信号。校验链路与权限判定批量分配入口assign_role_batch_for_userhandler.py先校验 LicenseLicenseHandler.raise_if_user_doesnt_have_feature(RBAC, ...)再校验 Subject 是否支持ALLOWED_SUBJECT_TYPE_BY_PRIORITY默认[auth.User, baserow_enterprise.Team]、是否在 Workspace 内、Scope 是否为 Workspace 子对象最后通过ROLE_ASSIGNABLE_OBJECT_MAP中对应的 UPDATE 操作做权限检查全部通过后才执行批量分配。权限判定入口RolePermissionManagerTypeenterprise/backend/src/baserow_enterprise/role/permission_manager.py实现了PermissionManagerType的三个核心方法check_multiple_permissions对一批 (actor, operation, context) 检查先调用RoleAssignmentHandler().get_roles_per_scope_for_actors获取每个 Actor 按层级排序的角色集合再用get_computed_roles计算 Context 上的实际角色最后把角色允许的操作名集合与请求的操作名比对允许则返回True否则返回PermissionDenied()permission_manager.py。get_permissions_object为前端生成每个操作默认是否允许 例外对象 ID 列表的权限对象形如{operation_name: {default: bool, exceptions: [id, ...]}}前端据此无需再向后端请求即可本地判断permission_manager.py。前端对应实现位于 enterprise/web-frontend/modules/baserow_enterprise/permissionManagerTypes.js并在 enterprise/web-frontend/modules/baserow_enterprise/plugin.js 中注册。filter_queryset依据权限对象对 Django QuerySet 做过滤——若默认允许则exclude(id__inexceptions)否则filter(id__inexceptions)无例外且默认拒绝时直接返回空集permission_manager.py。启用条件is_enabled通过LicenseHandler.workspace_has_feature(RBAC, workspace)判断该 Workspace 是否拥有 RBAC 企业特性未启用时该 manager 直接返回permission_manager.py。对应地RBAC 定义了自己的 Operation 类型见 enterprise/backend/src/baserow_enterprise/role/operations.pyworkspace.assign_role、workspace.read_role、application.read_role/application.update_role、database.table.read_role/database.table.update_role、database.table.view.read_role/database.table.view.update_role。这些操作正是ROLE_ASSIGNABLE_OBJECT_MAP中校验分配权限时使用的操作名。缓存与实时更新为提升性能角色分配结果通过local_cache缓存get_roles_per_scope、团队-用户映射、Workspace 用户权限等均以role_assignments_*为前缀做本地缓存所有写操作assign_role、remove_role都会通过clear_roles_from_local_cache装饰器清除相关缓存见 handler.py。角色分配变更后enterprise/backend/src/baserow_enterprise/role/receivers.py 中的信号处理器会转发permissions_updated信号进而通过 WebSocket 向受影响用户广播permissions_updated消息提示其刷新页面以获取最新权限。删除级联与注意事项原文档指出RoleAssignment的两个 GenericForeignKey 没有自动删除级联因此需要手动注册删除信号处理器。这一实现位于 enterprise/backend/src/baserow_enterprise/role/receivers.pycascade_subject_delete当任意 Subject 类型注册在subject_type_registry中的模型被删除时删除其作为 Subject 的全部 RoleAssignmentcascade_workspace_user_delete当WorkspaceUser被删除时清理该用户在该 Workspace 下的角色分配cascade_scope_delete当 Scope 对象ROLE_ASSIGNABLE_OBJECT_MAP中列出的对象类型以及字段权限内部使用的Field被删除时清理以其为 Scope 的全部 RoleAssignment。这些信号在 enterprise/backend/src/baserow_enterprise/apps.py 的应用就绪阶段通过connect_to_post_delete_signals_to_cascade_deletion_to_role_assignments()统一注册。已知限制与待办事项原文档明确列出以下未完成事项编写代码时需注意规避RBAC 领域的角色端点roles endpoint尚缺失部分命名欠佳有待改进计划使用HierarchicalMixin替代ObjectScopeType系统已接近支持自定义角色创建Role.workspace与Role.default字段已就位但尚未完全开放计划新增一个为 Workspace 中每个对象展示各 Actor 角色的调试页面帮助用户排查角色分配权限的实时更新目前只是部分实现——用户只会收到一条请刷新页面以获取新权限的消息尚做不到免刷新即时生效。配置项速查RBAC 模块支持通过 Django settings 覆盖以下常量见 constants.py 与 default_roles.py配置项默认值说明NO_ACCESS_ROLE_UIDNO_ACCESS无权限角色的 UIDREAD_ONLY_ROLE_UIDREAD_ONLY只读隐藏角色的 UIDNO_ROLE_LOW_PRIORITY_UIDNO_ROLE_LOW_PRIORITY低优先级占位角色的 UIDGET_ROLE_ASSIGNABLE_OBJECT_MAP内置四级映射workspace / application / database_table / database_view可分配角色的对象类型及对应读写操作名ALLOWED_SUBJECT_TYPE_BY_PRIORITY[auth.User, baserow_enterprise.Team]支持分配角色的 Subject 类型及优先级排序BASEROW_PERSONAL_VIEW_LOWEST_ROLE_ALLOWED无默认值必须显式设置允许使用个人视图的最低角色若设置为非默认角色 UID启动时会抛出ImproperlyConfiguredBASEROW_PERSONAL_VIEW_LOWEST_ROLE_ALLOWED的校验逻辑在 default_roles.py该值必须是user_role_uids即除内部角色外的全部默认角色 UID之一否则拒绝启动选定角色会被自动追加CreateAndUsePersonalViewOperationType操作。测试验证RBAC 模块在仓库中拥有较完整的测试覆盖可作为理解与二次开发的参考enterprise/backend/tests/baserow_enterprise_tests/role/test_role_handler.py覆盖角色分配的创建、唯一约束、查询、移除、批量分配与校验逻辑。其中test_create_role_assignment验证了 Workspace 级分配写入WorkspaceUser.permissions而表级分配写入RoleAssignment的双路径行为。enterprise/backend/tests/baserow_enterprise_tests/role/test_role_permission_manager.py覆盖RolePermissionManagerType的权限检查、权限对象生成与 queryset 过滤。enterprise/backend/tests/baserow_enterprise_tests/role/test_role_receivers.py 与 enterprise/backend/tests/baserow_enterprise_tests/ws/test_role_signals.py覆盖删除级联与实时信号广播。enterprise/backend/tests/baserow_enterprise_tests/api/role/test_role_views.py 与test_application_views_with_roles.py、test_views_filtered_by_roles.py覆盖角色相关 API 及角色过滤视图的行为。结语Baserow 的 RBAC 是一套建立在可插拔权限系统之上的细粒度授权方案通过RoleAssignment把角色 × 主体 × 作用域三元组落库以最近祖先优先、Actor 优先、Team 取并集、反向只读继承四条规则完成角色计算再交由RolePermissionManagerType统一裁决权限请求。理解这套规则与数据模型是在企业部署中正确配置团队权限、排查为什么用户能看到/看不到某张表等问题的关键而源码中预留的Role.workspace、default字段与明确的 TODO 清单也勾勒出了未来自定义角色等能力的演进方向。【免费下载链接】baserowBuild databases, automations, apps agents with AI — no code. Open source platform available on cloud and self-hosted. GDPR, HIPAA, SOC 2 compliant. Best Airtable alternative.项目地址: https://gitcode.com/GitHub_Trending/ba/baserow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考