☰
DooTask 项目任务权限点(ProjectPermission):4 主体 × 11 权限点的矩阵设计与实现
2026/10/15 11:58:44 网站建设 项目流程
  • 后端
  • 前端
  • 协同办公
  • 即时通讯
  • 企业应用

【免费下载链接】dootask

DooTask是一款开源在线项目任务管理工具,提供各类文档协作工具、在线思维导图、在线流程图、项目管理、任务分发、即时IM,文件管理等工具;同时消息功能使用非对称加密技术让你的沟通更安全。

项目地址:https://gitcode.com/gh_mirrors/do/dootask
点击查看免费下载

本篇围绕 DooTask 的项目任务权限体系展开:ProjectPermission表如何把「谁能对任务执行什么操作」拆成 4 类权限主体 × 11 个权限点的矩阵,矩阵以 JSON 形式按项目存储,并贯穿ProjectController中加列、改任务、归档、跨项目移动等操作的鉴权链路。读完本文,你将掌握权限矩阵的数据结构、默认值初始化、逐主体校验流程、配置 API 的参数含义,以及该体系的边界与限制。

一、ProjectPermission 解决什么问题

DooTask 用ProjectPermission表细化「谁能做什么任务级操作」:每条规则按4 类主体 + 11 个权限点的矩阵展开。规则只针对owner=0的普通成员——拥有者 / 管理员默认全开,不受矩阵限制。

需要明确它的边界(文档标注的 negative 约束):

  • 权限规则只控制任务操作(add / update / remove / move 等 11 个权限点),不控制项目设置(如改项目名称、项目成员管理等);
  • 拥有者 / 管理员的权限不可被 ProjectPermission 限制(默认全开);
  • 权限规则只能在「项目级」配置,不能按列、按标签细分;
  • 不支持「按部门角色」自动套用权限。

该概念在知识库中的适用范围为scope: admin,前置条件是操作者为项目拥有者(project_users.owner=1)或管理员(owner=2)。

二、数据模型:一张表 + 一个 JSON 矩阵

表结构

project_permissions表由迁移 create_project_permissions_table 创建,结构非常简单:

字段类型说明
idbigint 自增主键
project_idbigint,默认 0项目 ID
permissionstext完整权限矩阵的 JSON 序列化结果
created_at/updated_attimestamps时间戳

迁移里先判断Schema::hasTable('project_permissions'),存在则跳过,保证升级场景幂等。

模型层

模型 ProjectPermission 中,permissions字段通过 accessor 自动完成 JSON ↔ 数组转换:

public function getPermissionsAttribute($value) { return Base::json2array($value); }

11 个权限点以类常量定义(注意:数据库里的 key 是小写下划线形式):

const TASK_LIST_ADD = 'task_list_add'; // 添加列 const TASK_LIST_UPDATE = 'task_list_update'; // 修改列 const TASK_LIST_REMOVE = 'task_list_remove'; // 删除列 const TASK_LIST_SORT = 'task_list_sort'; // 列表排序 const TASK_ADD = 'task_add'; // 任务添加 const TASK_UPDATE = 'task_update'; // 任务更新 const TASK_TIME = 'task_time'; // 任务时间 const TASK_STATUS = 'task_status'; // 任务状态 const TASK_REMOVE = 'task_remove'; // 任务删除 const TASK_ARCHIVED = 'task_archived'; // 任务归档 const TASK_MOVE = 'task_move'; // 任务移动

4 类主体同样以常量 + 描述映射定义:

const PERMISSIONS = [ 'project_leader' => 1, // 项目负责人 'project_member' => 2, // 项目成员 'task_leader' => 3, // 任务负责人 'task_assist' => 4, // 任务协助人 ];

因此存储的 JSON 形如:{"task_add": [1, 2], "task_update": [1, 3, 4], ...}——每个权限点映射到一个「允许主体编码」数组。

三、4 类权限主体:判定依据是什么

主体编码主体源码中的判定依据
1project_leader项目拥有者 / 管理员ProjectController校验前$project->owner非空,即当前用户在该项目的project_users.owner为 1(负责人)或 2(管理员)。可参考 Project::isOwner() 的注释:owner=1为负责人,owner=2为管理员
2project_member项目内任意普通成员ProjectUser::whereProjectId(...)->whereUserid(...)->first()存在即通过
3task_leader该任务的负责人(project_task_users.owner=1)ProjectTask::isOwner()
4task_assist该任务的协作者(project_task_users.owner=0)ProjectTask::isAssister()

其中两个任务级判定值得展开:

  • isOwner():任务自身带owner标记时直接通过;若任务有parent_id,还会回查主任务——主任务的负责人也算子任务上的任务负责人,这是处理父子任务委托的常见做法;
  • isAssister():先沿parent_id循环上溯到主任务,再查project_task_users中是否存在owner=0的记录,即协助关系认定在主任务上。

四、11 个权限点与它们的调用入口

权限点含义
TASK_LIST_ADD加列(看板列)
TASK_LIST_UPDATE改列名 / 颜色
TASK_LIST_REMOVE删列
TASK_LIST_SORT列排序
TASK_ADD加任务
TASK_UPDATE改任务字段
TASK_TIME改计划时间
TASK_STATUS改工作流 / 完成
TASK_REMOVE删任务
TASK_ARCHIVED归档任务
TASK_MOVE跨列 / 跨项目移动

这些权限点不是摆设,而是被真实挂进业务入口的。从 ProjectController 的源码结构看,调用分布大致如下:

  • 列管理:加列、改列、删列、列排序分别校验TASK_LIST_ADD/TASK_LIST_UPDATE/TASK_LIST_REMOVE/TASK_LIST_SORT(见ProjectController.php#L1051、#L1104、#L1146、#L828);
  • 任务增改:创建任务校验TASK_ADD(#L2729、#L2829),修改任务字段校验TASK_UPDATE(#L2450);
  • 任务生命周期:删除校验TASK_REMOVE(#L2583、#L3213),归档校验TASK_ARCHIVED(#L3171),状态流转走动态权限键(#L3027);
  • 移动:跨列移动与跨项目移动都校验TASK_MOVE,且跨项目移动会双向校验——源项目要求TASK_MOVE、目标项目要求TASK_ADD(#L3511、#L3514);
  • 除 Web API 外,任务交接服务 ProjectTaskHandoffService 在交接前也会校验TASK_UPDATE。

两条对外 API 记录在 routes/api-map.md 中:api/project/permission(获取权限设置)与api/project/permission/update(更新权限设置)。

五、默认权限矩阵:新建项目时是什么

文档给出的默认值描述是:新建项目时,project_member对 TASK_ADD / TASK_UPDATE / TASK_STATUS / TASK_TIME / TASK_ARCHIVED / TASK_MOVE / TASK_LIST_SORT 全开,task_leader/task_assist全开,列增删改仅拥有者 / 管理员。

而当前仓库源码中 initPermissions() 的实际默认矩阵是:

权限点默认允许的主体
task_list_add/task_list_update/task_list_sort/task_add项目负责人(1) + 项目成员(2)
task_list_remove仅项目负责人(1)
task_update/task_time项目负责人(1) + 任务负责人(3) + 任务协助人(4)
task_status/task_remove/task_archived/task_move项目负责人(1) + 任务负责人(3)

可以看到,默认值的核心设计意图是一致的:列管理偏向项目管理者,任务内容编辑向「任务自己人」(负责人/协助人)开放,状态类操作更收敛。但注意两点差异:其一,project_member的默认开放范围在源码中仅覆盖列排序等 4 个权限点,并未对任务字段修改、状态流转全开;其二,task_assist默认只有task_update/task_time两项。知识库文档标注last_verified: v1.7.90,若你运行的版本默认值与上述不同,请以initPermissions()的当前源码为准——这是唯一会写入新项目的默认矩阵。

六、校验流程:userTaskPermission 如何逐主体判定

核心方法是 userTaskPermission(),签名是(Project $project, $action, ProjectTask $task = null)。它对 11 个权限点走同一条 switch 分支,判定顺序如下:

  1. 取该 action 当前允许的主体数组:getPermission($project->id, $action)先调initPermissions()(不存在则按默认矩阵落库),再取对应 key;若 key 不存在直接抛ApiException('项目权限设置不存在');
  2. 项目负责人:主体数组含1且$project->owner非空(当前用户是 owner=1 或 2)→ 通过;
  3. 项目成员:主体数组含2且project_users中查得到该用户 → 通过;
  4. 任务负责人:主体数组含3且传入了$task且$task->isOwner()→ 通过;
  5. 任务协助人:主体数组含4且$task->isAssister()→ 通过;
  6. 全部不满足:把允许主体翻译成描述后倒序拼接,抛ApiException("仅限项目负责人、任务负责人操作")这类带多语言描述的拒绝信息。

这里有一个容易误解的点:拥有者「不被矩阵限制」并不是硬编码的特权,而是矩阵默认值保证了这一点——即使project_leader主体被从某个权限点中移除,拥有者通常仍是项目成员(project_users中存在 owner=1 的记录),仍会走第 3 步project_member分支通过(前提是该主体仍在允许列表中)。从源码结构看,userTaskPermission本身并没有对 owner=1/2 做绕过。

另外注意主体判定的短路特性:四个主体按 leader → member → task_leader → task_assist 顺序检查,任一命中即返回,project_leader排在最前,保证管理角色优先。

七、在哪配:配置入口与 API

配置面板

  • 桌面端:项目设置 →「权限规则」面板,用矩阵勾选的方式编辑:每个权限点 × 每类主体;
  • 操作者需为项目拥有者(owner=1)或管理员(owner=2)。

读取与更新 API

  • 获取:api/project/permission(参数project_id),实现见 ProjectController——先校验当前用户在该项目中,然后initPermissions()返回完整矩阵(不存在则先按默认值落库),因此该接口天然幂等。
  • 更新:api/project/permission/update(project_id+ 各权限点数组),控制器实现:
$permissions = Request::only([ ProjectPermission::TASK_LIST_ADD, ProjectPermission::TASK_LIST_UPDATE, ProjectPermission::TASK_LIST_REMOVE, ProjectPermission::TASK_LIST_SORT, ProjectPermission::TASK_ADD, ProjectPermission::TASK_UPDATE, ProjectPermission::TASK_TIME, ProjectPermission::TASK_STATUS, ProjectPermission::TASK_REMOVE, ProjectPermission::TASK_ARCHIVED, ProjectPermission::TASK_MOVE, ]); $projectPermission = ProjectPermission::updatePermissions($projectId, Base::newArrayRecursive('intval', $permissions));

参数说明:每个权限点 key 传允许主体编码的数组,如task_add[]=1&task_add[]=2(允许项目负责人和项目成员);Request::only只放行 11 个合法 key,intval递归清洗保证值只能是主体编码。

updatePermissions() 的合并语义值得注意:

$mergedPermissions = empty($newPermissions) ? $currentPermissions : array_merge($currentPermissions, $newPermissions);

即请求中没有出现的权限点保持原值不变,只有传了的才覆盖——部分更新是安全的,前端只需提交用户改动的格子。从当前仓库源码看,该接口入口只校验调用者是项目成员,文档中标注的「仅限拥有者 / 管理员配置」这一前置更可能由前端权限面板控制,调用 API 时请以你的部署版本实际行为为准。

八、设计取舍与不支持的场景

这套矩阵是典型的「粗粒度、易理解」设计,其明确不做的事与文档的 negative 清单一致:

  • 不能按列、按标签做细粒度限制:权限点是项目级的,userTaskPermission的判定参数里没有任何列(ProjectColumn)或标签(ProjectTaskTag)维度;
  • 不能限制拥有者 / 管理员:默认矩阵中project_leader主体出现在全部 11 个权限点,且拥有者同时是项目成员,双重兜底;
  • 不支持「按部门角色」自动套用权限:主体只有 4 类静态编码,没有与UserDepartment联动的角色映射;
  • 矩阵只约束任务操作:项目设置、成员管理等入口不走userTaskPermission。

对集成方而言,这意味着如果你想做「某列只读」之类的需求,需要在上层业务逻辑自行叠加判断,而不是指望project_permissions表。

参考文件

  • 权限模型与校验核心:app/Models/ProjectPermission.php
  • 表结构迁移:database/migrations/2023_11_20_214409_create_project_permissions_table.php
  • 任务级判定(isOwner / isAssister):app/Models/ProjectTask.php
  • 项目 owner 语义(owner=1/2):app/Models/ProjectUser.php、app/Models/Project.php
  • 鉴权调用点与配置 API:app/Http/Controllers/Api/ProjectController.php
  • API 清单:routes/api-map.md
  • 后端
  • 前端
  • 协同办公
  • 即时通讯
  • 企业应用

【免费下载链接】dootask

DooTask是一款开源在线项目任务管理工具,提供各类文档协作工具、在线思维导图、在线流程图、项目管理、任务分发、即时IM,文件管理等工具;同时消息功能使用非对称加密技术让你的沟通更安全。

项目地址:https://gitcode.com/gh_mirrors/do/dootask
点击查看免费下载

相关推荐

上一篇:Tiled JSON Map 格式完整参考:从字段定义、导出流程到源码级实现解析
下一篇:PX4 计算机视觉功能全解析:Optical Flow、Motion Capture、VIO 与防碰撞

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询