流量没有了,强制授权——管理员为什么能越权操作辖区内的流程
政务审批系统里,普通操作员只能看自己的任务。但任务可能挂在某个请假的人名下三天没人动,或者分配逻辑出错导致任务到了不该接的人手里。这时候管理员需要一个"强制授权"能力——越过权限限制,看到并操作辖区范围内的所有流程任务。
文章目录
- 流量没有了,强制授权——管理员为什么能越权操作辖区内的流程
-
- 一、问题:任务卡住了,必须有人能救火
- 二、三级数据权限——不是所有人能看所有任务
- 三、BMLD角色——部门领导的权限放大
- 四、selectAllRun——管理员的全量视图
- 五、前端样式——跑马灯防屏幕休眠
- 六、强制授权的完整调用链
- 七、这套设计的价值
- 八、结语
一、问题:任务卡住了,必须有人能救火
工作流分配不是完美的。三种常见情况:
这时候需要一种能力:某个人可以不依赖"分配给自己"这个条件,直接看到并操作辖区内的所有任务。就是"强制授权"。
二、三级数据权限——不是所有人能看所有任务
— 等级1:普通操作员——只能看到自己经办的任务
select * from act_ru_task where assignee_ = #{userId};
— 等级2:部门领导——能看到自己+本单位所有人员的任务
select * from act_ru_task
where assignee_ = #{userId}
or assignee_ in (
select psn_id from op_person
where dept_id in (
select dept_id from op_person
where psn_id = #{userId}
and exists (
select 1 from role_person_map
where role_id = 'BMLD' and psn_id = op_person.psn_id
)
)
);
— 等级3:管理员/全区——能看到本单位(含下级单位)所有任务
select * from act_ru_task
where assignee_ in (
select psn_id from op_person
where dept_id in (select unit_id from op_unit where unit_id like #{areaNo} || '%')
);
三级权限的逻辑:
| 个人 | 普通操作员 | assignee_ = 自己 |
| 部门 | 部门领导(BMLD) | 自己 + 同部门所有人的任务 |
| 辖区 | 管理员 | 本辖区所有单位的任务 |
权限不是写在Java代码里的,是用SQL的 exists + in 子查询控制的。同一个人,查任务时走的SQL不同,看到的结果集就不同。
三、BMLD角色——部门领导的权限放大
— selectbyuseridrun2 的核心过滤条件
and exists (
select 1 from ACT_HI_TASKINST b
where a.PROC_INST_ID_ = b.PROC_INST_ID_
and (
b.ASSIGNEE_ = #{userId} — ① 自己的任务
or b.ASSIGNEE_ in ( — ② 同级单位所有人员的任务
select psn_id from op_person
where dept_id in (
select dept_id from op_person c
where psn_id = #{userId}
and exists (
select 1 from role_person_map
where role_id = 'BMLD'
and psn_id = c.psn_id
)
)
)
)
)
这段SQL做三件事:
如果这个人没有 BMLD 角色,exists(select 1… role_id='BMLD') 返回空,in() 的子查询无结果,条件退化为 ASSIGNEE_ = #{userId} ——和普通操作员一样。
这就是"强制授权"的实现——不改任何业务逻辑,只改查询条件的SQL。
四、selectAllRun——管理员的全量视图
runingAll.jsp 页面用的是 selectAllRun 这个查询:
select a.PROC_INST_ID_, a.PROC_DEF_ID_, a.START_TIME_,
b.matter_name, c.name_ taskname, c.id_ as taskid,
c.create_time_ taskcreatetime,
case when (select psn_name from op_person t where t.psn_id=c.assignee_) is null
then (select unit_name from op_unit where unit_id = substr(c.assignee_, INSTR(c.assignee_, '#', '1') + 1))
|| '-' || (select role_name from op_role where role_id = substr(c.assignee_, 2, INSTR(c.assignee_, '#', '1') – 2))
else (select psn_name from op_person t where t.psn_id=c.assignee_)
end as psn_name
from ACT_HI_PROCINST a, v_business_table b, act_ru_task c
where a.END_TIME_ is null
and a.proc_inst_id_ = b.proc_inst_id_(+)
and a.proc_inst_id_ = c.proc_inst_id_
and exists (
select 1 from act_hi_taskinst
where proc_inst_id_ = a.proc_inst_id_
and assignee_ in (
select aa.psn_id from op_person aa, ab01 bb
where aa.dept_id = bb.unit_id
)
)
这个查询没有 userId 参数——它就是全单位的。exists 子查询里的 assignee_ in (本单位所有人员) 决定了这个页面展示的是本单位辖区范围内所有在跑的任务,不管是谁的。
页面上能看到:
- 事项名称(参保登记、待遇核定……)
- 当前任务名称(初审、复核……)
- 当前任务处理人(具体到人还是角色)
- 任务创建时间
管理员在这个页面可以做两件事:直接处理(把任务接过来自己处理),或改派(把任务改分配给另一个人)。
五、前端样式——跑马灯防屏幕休眠
runingAll.jsp 还有一个隐藏的设计:自动刷新。
// 每30秒自动刷新一次——做"流量没有了"时的跑马灯效果
setInterval(function() {
location.reload();
}, 30000);
这个设计不是为了体验——是为了防屏幕休眠。政务大厅的监控屏幕如果不动,系统会自动休眠或被检测为离线。30秒一刷,大屏幕永远显示最新数据,永远不会休眠。
"流量没有了"是内部调侃——任务量少的时候页面几乎没变化,但刷新不能停,因为刷新的目的从来不是为了看新数据,是保持大屏存活。
六、强制授权的完整调用链
管理员打开 runingAll.jsp
│
▼
selectAllRun → 查本单位辖区所有在办任务
│
▼
管理员看到某任务卡住了(如请假的张三名下有3个待办)
│
▼
管理员点"处理" → 调用 claim(taskid, 管理员id)
│ → 把任务的 assignee_ 从 #role#dept 改为 管理员本人的psn_id
│ → 管理员进入处理界面 → 处理完成 → 流程流转
│
▼ 或者
管理员点"改派" → 调用 transferAssignee(taskid, 另一个人id)
│ → 把任务分配给别人
│
▼
old_task 表记录改派日志(追溯审计)
关键:管理员处理完或改派完的任务,流程会正常流转——下一个环节仍然走自动分配逻辑(prc_alloc),管理员不会一直持有这个任务。
七、这套设计的价值
权限控制不在Java代码里,在SQL的where条件里。 三个等级对应三条SQL,改权限策略不改业务逻辑。
BMLD角色是开关——同一个操作员,有BMLD角色就能看全部门的任务,没有就只能看自己的。角色赋权或撤权即时生效,因为每次查询都在判断 exists(select 1 from role_person_map where role_id='BMLD')。
改派可追溯——每次强制改派都写 old_task 表。审计时问"张三的参保登记审批为什么变成李四处理的",查 old_task 就能看到。不是你手动把 assignee 改了又改,是从 task→old_task→old_task 有一条完整的改派链。
八、结语
强制授权的本质不是"超级管理员拥有一切权限",而是角色决定SQL的where条件范围。同一个查询方法,不同角色走不同的子查询,返回不同的结果集。没有写死权限的if-else,权限策略完整体现在SQL里。改权限只需要改角色表中的一条记录,SQL自动走不同的分支。
网硕互联帮助中心



评论前必须登录!
注册