ToolJet 权限体系深入解析:基于用户组(User Groups)的 RBAC 访问控制实战指南
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
在 ToolJet 中,权限管理以基于角色的访问控制(RBAC)为核心:管理员负责邀请用户进入工作区(Workspace),并将他们分配到特定的用户组(Groups),每个组都绑定一组权限(Permissions),用来决定成员对 App、文件夹、工作区变量等资源的访问级别。本文将以 ToolJet 2.50.0-LTS 版本的官方文档 permissions.md 为主线,结合仓库中server/src/modules/group-permissions的源码实现,系统讲解默认组、自定义组、细粒度权限以及实际运维中的落地步骤,帮助你像管理员一样精确控制谁能在你的 ToolJet 工作区里做什么。
一、RBAC 核心模型:资源、组与权限的关系
在 ToolJet 中,整个权限体系由三类基本元素构成,理解了这三者的关系就理解了权限系统的全貌:
| 元素 | 说明 |
|---|---|
| Users(用户) | 工作区成员,每个用户关联一个邮箱,可以被加入一个或多个组 |
| Groups(用户组) | 权限的载体。默认存在All Users与Admin两个组,此外可创建如 Support、Engineering 等自定义组 |
| Resources(资源) | 管理员可以设置权限的对象,包括Apps(应用)、Folders(文件夹)与Workspace Variables(工作区变量) |
| Permissions(权限) | 施加在资源上的操作能力,核心是Create(创建)、Update(更新)、Delete(删除),在 App 级别则细化为View(查看)与Edit(编辑) |
这一模型在服务端源码中有着精确的对应。在 server/src/modules/group-permissions/constants/index.ts 中,定义了组的类型与内置角色:
export enum GROUP_PERMISSIONS_TYPE { DEFAULT = 'default', // 内置默认组,不可删除 CUSTOM_GROUP = 'custom', // 自定义组(付费计划支持) } export enum USER_ROLE { END_USER = 'end-user', ADMIN = 'admin', BUILDER = 'builder', } export enum ResourceType { APP = 'app', DATA_SOURCE = 'data_source', WORKFLOWS = 'workflow', FOLDER = 'folder', MODULE = 'module', WORKFLOW_FOLDER = 'workflow_folder', MODULE_FOLDER = 'module_folder', }从源码结构看,ToolJet 的权限管控资源已经从文档中提到的"Apps、Folders、Workspace Variables"扩展到了Data Sources、Workflows、Modules及其各自的文件夹维度,权限粒度也从"Create/Update/Delete"演进为更细的canEdit、canView、canConfigure、canUse等操作位。
二、内置默认组:All Users 与 Admin
每个 ToolJet 工作区在创建时都会自动生成两个默认用户组,它们由服务端的createDefaultGroups逻辑在组织初始化时批量创建(见 util.service.ts):
1. All Users(所有用户)
- 包含工作区内的全部用户与管理员,新用户被邀请时默认加入此组;
- 组的成员列表不可手动增删(因为它的含义就是"所有人");
- 管理员可以编辑该组的权限,从而全局性地影响所有用户的能力。
2. Admin(管理员)
- 默认包含所有管理员,管理员可以继续添加或移除组内成员;
- 该组对工作区内的所有 App 默认拥有Edit权限,并具备创建/删除 App、创建文件夹等完整能力;
- 组的权限开关默认全开,且修改被禁用——它代表的是工作区最高权限集合。
这两组的权限基线定义在 DEFAULT_GROUP_PERMISSIONS 中。例如管理员组的核心权限位如下:
ADMIN: { name: USER_ROLE.ADMIN, type: GROUP_PERMISSIONS_TYPE.DEFAULT, appCreate: true, appDelete: true, folderCreate: true, folderDelete: true, orgConstantCRUD: true, // 工作区常量(Workspace Constants)增删改 tjdbCRUD: true, // ToolJet Database 增删改 dataSourceCreate: true, dataSourceDelete: true, isBuilderLevel: true, // 判定为"构建者"级别,可访问开发/暂存环境 appPromote: true, // 应用提级(Promote) appRelease: true, // 应用发布(Release) }而End-user(终端用户)角色的所有布尔权限位均为false,仅能消费已发布(Released)的内容。此外,源码中的HUMANIZED_USER_LIST = ['End-user', 'Builder', 'Admin']与USER_ROLE被用作保留字校验:validateCreateGroupOperation与validateUpdateGroupOperation(见 util.service.ts)会拒绝使用这些名称创建或重命名自定义组,防止与内置角色混淆。
注意:2.50.0-LTS 版本在文档层面强调"两个默认组",但服务端已经引入了第三个内置角色Builder(构建者)。可以推断,在较新的版本中,默认组已扩展为 End-user / Admin / Builder 三组,
createDefaultGroups正是遍历USER_ROLE枚举逐个创建的。若你使用的版本界面仍只显示两个组,请以实际版本为准。
三、自定义组与细粒度权限设置
默认组的权限是"一刀切"的,而自定义组是 ToolJet 实现最小权限原则(Principle of Least Privilege)的核心工具。官方文档给出了一个典型场景:
创建一个名为Finance Team的自定义组,仅授予其访问财务相关 App 和工作区变量的权限。邀请新用户时直接将其分配到该组,确保他们只能访问完成本职工作所需的最小资源集合。
3.1 创建自定义组(付费计划专属)
根据 manage-users-groups.md 的说明,创建新组的选项仅在付费计划中可用。操作步骤:
- 进入仪表盘左侧边栏的Workspace Settings→Groups页面;
- 点击Create new group按钮;
- 输入组名称,点击Create Group;
- 创建完成后,为该组配置Apps、Users、Permissions、Data Sources四个维度的内容。
这一"付费门控"在源码中同样有体现:getAllGroupByOrganization在许可证未启用customGroupsEnabled功能时,会把所有自定义组标记为disabled(见 util.service.ts);而addUsersToGroup、updateGroup也会在许可证无效时对自定义组抛出ForbiddenException。
3.2 组的四个配置区块
每一个用户组在界面上都有四个配置区域,对应着不同资源维度的授权:
| 区块 | 可配置内容 | 谁能配置 |
|---|---|---|
| Apps | 为组添加/移除任意数量的 App,并为每个 App 单独设置View或Edit权限 | Admins、Super Admins |
| Users | 为组添加/移除任意数量的用户 | Admins、Super Admins |
| Permissions | 细粒度权限:Create/Delete Apps、Create/Update/Delete Folders、Create/Update/Delete 工作区常量、Create/Delete Data Sources | Admins、Super Admins |
| Data Sources | 定义该组用户可**查看(View)或编辑(Edit)**哪些数据源 | 仅 Admins、Super Admins |
3.3 App 级权限:View 与 Edit
在Apps区块中,同一个组内的不同 App 可以拥有不同的权限级别:
- View:仅能查看/使用该 App(运行已发布版本);
- Edit:可以打开并修改该 App 的定义。
在服务端,这一关系由多对多关联表承载。仓库中 apps_group_permissions.entity.ts 保存"组-应用"的授权记录,app.entity.ts、app_base.entity.ts 等实体则定义了应用本身的属性。而真正决定"当前用户能否执行某操作"的,是位于 server/src/modules/casl/casl-ability.factory.ts 的 CASL 能力工厂——它根据用户所属组的权限位动态构建能力集合,再由 ability/guard.ts 等守卫在请求进入控制器前完成鉴权。
3.4 资源级默认授权矩阵
在创建默认组时,除了布尔型权限位,ToolJet 还会为每个组生成资源级(granular)默认权限,定义在 DEFAULT_RESOURCE_PERMISSIONS 中。以 App 资源为例,三个角色的默认差异如下:
| 权限项 | Admin | Builder | End-user |
|---|---|---|---|
canEdit | true | true | false |
canView | false(Edit 隐含 View) | false | true |
canAccessDevelopment | true | true | false |
canAccessStaging | true | true | false |
canAccessProduction | true | false | false |
canAccessReleased | true | true | true |
可以看到一个关键设计:End-user 默认只能访问 Released(已发布)版本的 App,无法触碰开发(Development)与暂存(Staging)环境;而 Builder 虽然可以编辑应用,但默认无权访问生产环境——这是为了防止未经验证的应用改动直接影响线上数据。文件夹(Folder)维度同样有三档选择:canEditFolder(编辑文件夹)、canEditApps(编辑其中应用)、canViewApps(仅查看其中应用),且只保存被选中档位的布尔值,隐含的低档权限在运行时推导(见 granular_permissions.ts 中各资源的显示名称映射)。
四、用户管理的完整操作闭环
权限体系的落地离不开用户生命周期管理。以下操作均在Workspace Settings → Users页面完成:
4.1 邀请用户(Invite)
- 点击 Users 页面右上角的Add users按钮,在右侧抽屉中选择Invite with email标签页;
- 填写Full Name、Email address,并从下拉框中选择要分配的用户组(All Users为默认组,也可选择新建的自定义组);
- 点击Invite Users后,系统会向该邮箱发送包含Invite Link的邀请邮件,用户通过链接加入工作区后,状态由Invited变为Active;
- 可点击 Invited 状态旁的Copy link复制邀请链接;也可通过Bulk Invite标签页上传 CSV 模板批量邀请用户。
4.2 编辑用户与归档/恢复
- Edit user details:通过用户行右侧的 kebab 菜单进入,可在抽屉中为成员添加或移除所属组,修改后点击Update保存;
- Archive:归档用户将禁用其对该工作区的访问,状态变为Archived。注意,被归档的用户仍可被邀请到其他工作区,除非在实例级Settings页面(Super Admin)中被实例级归档;
- Unarchive:恢复归档用户的访问权。若用户曾在实例级被归档,那么从任一工作区恢复其状态时会连带解除实例级归档;恢复后状态变为Invited,需要重新通过邮件链接加入。
在服务端,归档相关的状态常量定义于 server/src/modules/users/constants/lifecycle.ts(USER_STATUS与WORKSPACE_USER_STATUS),而addUsersToGroup在添加成员时会显式排除已归档用户(见 util.service.ts),从数据层保证了归档用户无法被重新加入组。
4.3 删除自定义组
在Groups页面点击组行右侧的Delete,确认后(点击Yes)即可删除自定义组。源码层面,deleteGroup会拒绝删除type === GROUP_PERMISSIONS_TYPE.DEFAULT的默认组,抛出DEFAULT_GROUP_UPDATE_NOT_ALLOWED错误(见 util.service.ts)——默认组永远无法被删除,这是数据完整性的硬约束。
五、安全实践:最小权限与公开访问
综合官方文档与源码,在 ToolJet 中落实安全访问控制的推荐路径是:
- 先规划再建组:按业务职能(Finance、Support、Engineering)而非按个人建立自定义组,一个用户可属于多个组,权限取并集;
- 用组隔离资源:为每个组精确配置 Apps、Data Sources、工作区常量的 View/Edit 权限,遵循最小权限原则;
- 邀请即授权:新用户邀请流程中直接分配对应组,避免"先全量放行、后逐个回收";
- 审慎处理公开访问:文档指出,你还可以将 App设为公开(Public),使其无需登录即可访问——这适用于对外展示类应用,但应只针对只读场景,切勿将含敏感数据的内部应用公开;
- 借助审计日志回溯:工作区内 Admin、Super Admin 或任何用户的全部操作都会被记录在Audit logs中,包括用户与组的管理行为。当发生权限事故时,审计日志是定位"谁在何时改了什么"的第一手证据。相关实现在 server/src/modules/group-permissions/util.service.ts 中可见——每次更新、删除组或移除成员时,都会通过
RequestContext.setLocals写入包含userId、organizationId、resourceId、resourceName的审计上下文。
六、总结
ToolJet 的权限体系是一个以用户组为授权单元、以资源操作位为粒度的 RBAC 实现:内置的 All Users 与 Admin 组提供了开箱即用的基线,付费计划下的自定义组则允许工作区按业务边界精细切分权限。从 constants/index.ts 中的默认权限矩阵,到 util.service.ts 中的组生命周期管理,再到 CASL 能力工厂的运行时鉴权,整条链路在服务端都有清晰的代码支撑。掌握了"组即权限集合、用户多组取并集、资源分维授权、默认组不可删、终端用户仅见已发布内容"这五个要点,你就能在自己的工作区中构建一套既灵活又安全的访问控制方案。
【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 🚀项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考