后台系统最怕什么?不是并发扛不住,也不是慢SQL查不出来,而是用户明明只该看自己负责的那三十条工单,结果通过一个列表查询,把全公司三十万条工单的明细全拉走了。上个月我们刚处理过一起这种问题:销售部普通专员在订单管理页面点了一下“导出”,拿到的Excel里包含所有大区的客户,查了权限配置,菜单权限、按钮权限全都没问题,问题就出在数据层没有任何行级隔离。
数据权限控制,说到底是把“一条SQL能返回哪些行”这件事从业务代码里解耦出来,让它成为一套独立、可统一治理的规则。很多团队一提权限就默认是RBAC、菜单、接口鉴权,但这些只解决“你能不能点某个入口”的问题。进入业务操作之后,真正决定系统安全边界的,反而是每一行数据是否按照“当前登录人是谁、属于哪个部门、什么角色、什么数据范围”被正确过滤。
这篇文章会从一次实际改造讲起:数据权限控制的整体分层思路,怎么和Spring Boot、MyBatis这类常见框架集成,以及在落地过程中踩过的坑和沉淀下来的排查方法。适合后台管理系统、中后台SaaS产品的后端开发、架构师参考。
1. 从业务痛点谈起:功能权限之外,为什么还需要一套数据权限控制
1.1 数据权限和功能权限的边界
功能权限和数据权限经常混在一起聊,但它们在实现上完全是两码事。功能权限管的是“端点”,比如某个用户能不能访问订单管理页、能不能点击删除按钮;数据权限管的是“行”,同一个订单列表页,销售专员看自己的订单,销售主管看本部门的订单,大区经理看整个大区的订单。
功能权限可以用接口拦截、注解鉴权、菜单配置来完成,粒度到URL和按钮就够了。数据权限则必须下沉到数据访问层,否则再严格的接口鉴权也拦不住一个拼接不当的查询。最常见的翻车姿势是先查出所有数据再在Java内存里按部门过滤。这种写法在演示环境没问题,但数据量一旦上来,全表扫描加内存过滤会让数据库和JVM一起遭殃,而且分页会变得极其难做——你还没过滤完,页数就已经不对了。
我在改造之前先划清了一条线:功能权限由统一网关和Spring Security处理,数据权限由专门的数据权限引擎处理,两者互不替代。网关管不了SQL返回的行数,SQL拦截器也代替不了登录认证。边界清楚了,才不会在方案设计阶段陷入“我到底该在哪一层做权限”的争论。
1.2 常见实现路线:ORM插件、SQL改写、应用层过滤
业界做数据权限,大致有三条路,我仔细对比过它们的优劣势。
第一种是直接在业务SQL里手写权限条件,比如每个Mapper的查询都手动拼上WHERE dept_id = ?。看起来直接,但问题很快会暴露:几十个Mapper、几百个查询,每个开发对“本部门”的理解不一样,有人用dept_id = 当前部门,有人用dept_id IN (子部门),还有人漏加了条件。结果是权限规则散落在各处,审计无从下手,越权只是时间问题。
第二种是应用层过滤,先查出所有数据再在代码里筛选。这种方案只适合数据量小、无分页的管理端小表格,不适用于生产核心列表。数据量一上去,数据库压力成倍增长,而且统计报表会连同不该有的数据一起统计,结果不可信。
第三种是基于ORM拦截器做SQL改写,这也是我最终采用的方案。业务Mapper里只需要写正常的业务查询,数据权限引擎在SQL执行前自动解析当前用户的规则,把权限条件拼接到原SQL后。这样权限规则收敛到一处,新接一个查询不需要开发记“别忘了加权限”,框架层面就能兜底。
1.3 我想要的系统边界与核心目标
动手之前,我给这套系统定了四个目标,后面所有设计决策都对标这四个目标来验证。
- 可复用:权限规则不能绑死在某一套业务表上,换项目、换库表时规则模型还能用。
- 可运维:规则调整不需要改代码发版,管理员在后台配置就能生效。
- 可追溯:每一条被拦截的SQL都能查到“按什么规则过滤、过滤后影响范围多大”。
- 可兜底:即使开发漏标注解,框架也能用默认策略拦住高风险查询,而不是裸奔。
这四个目标直接决定了分层架构的选择。如果不追求可复用,直接在拦截器里写死几个if分支就能跑;如果不追求可运维,规则做进枚举常量就行。但数据权限这种横切逻辑,一旦散落或写死,后续每次组织架构调整都是一次事故高发期。所以值得在最开始用分层的方式把模型搭稳。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 分层设计:把混乱的权限规则拆成三个层次
2.1 策略层:数据范围规则的抽象
我设计的第一层是策略层,核心是回答一个问题:系统中的数据范围到底有哪几种。
从业务收敛来看,绝大多数系统的数据范围逃不出这几种:仅本人数据、本部门数据、本部门及下属部门数据、全部数据、指定部门或指定人员数据。如果业务复杂,还可以有“按自定义SQL片段”的扩展方式。
我提供了五档标准范围:
| 范围类型 | 含义 | 典型用户 |
|---|---|---|
| ALL | 全部数据 | 超级管理员、审计角色 |
| DEPT | 本部门数据 | 部门主管 |
| DEPT_AND_SUB | 本部门及下级部门数据 | 区域经理 |
| SELF | 仅本人数据 | 普通专员、销售顾问 |
| CUSTOM | 自定义部门/人员集合 | 跨部门协作者、项目经理 |
在策略
