数据权限深度定制、源码解析与实战落地)
在上一篇《RuoYi二次开发常用技巧与功能拓展》中我们讲解了基础开发规范、CRUD提效技巧与通用功能拓展。而在企业级后台系统中功能权限只解决“能不能点”数据权限才解决“能不能看”。绝大多数OA、ERP、政务、国资、供应链系统的核心安全需求都是行级数据隔离普通员工只能看自己的数据、部门主管看本部门数据、管理员看全量数据。本文为系列第二篇深度拆解 RuoYi 数据权限底层原理、五种默认权限规则、自定义数据权限开发、特殊业务场景适配、常见Bug与终极避坑方案所有代码均可直接用于生产环境。一、先搞懂RuoYi 功能权限 vs 数据权限很多新手开发者容易混淆两种权限导致权限配置混乱、数据越权等问题二者核心区别如下1.1 功能权限按钮/菜单权限控制用户能否访问某个接口、页面、按钮属于「操作权限」。实现方式基于 PreAuthorize 注解、菜单权限标识控制例如PreAuthorize(“hasPermission(‘biz:goods:list’)”)。特点全局固定与数据本身无关有权限就能操作全部数据。1.2 数据权限行级权限控制用户能查询、操作哪些数据属于「数据范围权限」。实现方式MyBatis 拦截器动态拼接 SQL 条件自动过滤数据无需手动写判断。特点同接口、同权限的不同用户查询结果不同实现数据隔离。二、RuoYi 原生五种数据权限规则核心基础RuoYi 内置五种开箱即用的数据权限范围也是企业项目最常用的规则绑定在角色维度一个角色对应一种数据范围。权限类型常量标识权限说明适用场景全部数据权限data_scope1可查询所有数据无过滤超级管理员、平台总管理员自定义数据权限data_scope2手动指定可查看的部门列表跨部门审批、专项管理员本部门数据权限data_scope3仅查询当前所属部门数据部门主管、部门运营本部门及以下data_scope4查询当前部门下级所有部门数据多级部门管理层、区域负责人仅本人数据权限data_scope5只查询自己创建的数据普通员工、基础业务人员核心知识点数据权限是角色级配置一个用户多个角色时权限会取并集以最大数据范围为准。三、底层原理数据权限如何自动生效RuoYi 数据权限核心基于 MyBatis 插件拦截器 实现无需开发者手动拼接 SQL全程自动处理。3.1 执行流程用户登录框架缓存当前用户角色、部门、数据范围配置业务 Mapper 执行查询 SQL 时触发数据权限拦截器 DataScopeInterceptor拦截器判断当前接口是否需要数据权限过滤根据角色对应的 data_scope 类型动态拼接 WHERE 过滤条件MyBatis 执行拼接后的 SQL返回过滤后的数据集。3.2 默认过滤规则源码逻辑框架默认依赖数据表的 create_by本人数据、dept_id部门数据两个字段实现过滤这也是上一篇文章强调业务表必须携带通用字段的核心原因。简单对应逻辑仅本人create_by 当前登录用户名本部门dept_id 当前用户部门ID本部门及下级dept_id IN (当前部门及所有子部门ID)四、标准数据权限快速落地零代码开启很多开发者不知道RuoYi 新增业务模块无需写一行代码即可开启数据权限只需遵循规范配置即可。4.1 前置条件业务数据表必须包含两个核心字段create_by varchar(64)创建人账号dept_id bigint数据所属部门ID通过代码生成器生成的代码会自动适配数据权限拦截规则。4.2 开启方式在业务 Mapper 的 List 查询方法上添加数据权限注解/** * 查询商品列表 */ DataScope ListBizGoodsselectBizGoodsList(BizGoods bizGoods);仅此一行注解自动拥有全部五种数据权限过滤能力。4.3 后台角色配置系统管理 角色管理 数据权限选择对应权限范围保存后立即生效无需重启服务。五、高阶实战自定义数据权限场景开发原生五种规则无法覆盖所有业务实战中高频出现按片区、按门店、按项目、按自定义维度过滤数据。下面讲解企业最常用的自定义字段数据权限通用方案不改动源码、完全拓展实现。5.1 业务场景例如门店管理系统不同区域经理只能查看自己负责的门店数据不再以部门为维度而是以 shop_id 门店ID作为数据隔离维度。5.2 实现思路AOP自定义注解自定义数据权限注解标记需要门店权限过滤的接口用户维度存储可操作的门店ID集合通过 MyBatis 拦截器或 AOP 动态拼接 SQL 过滤条件实现基于门店的行级数据隔离。5.3 完整可落地代码第一步自定义注解Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)public interface ShopDataScope{}第二步自定义数据权限拦截器继承原生拦截器拓展逻辑重写过滤规则支持 shop_id 过滤。核心逻辑获取当前用户已分配门店列表拼接 SQLshop_id IN (1,2,3)。第三步Mapper 方法添加注解ShopDataScope ListBizShopselectBizShopList(BizShop bizShop);至此完成自定义维度的数据权限隔离完全解耦框架源码支持后续无限拓展。六、特殊业务场景适配方案6.1 详情、编辑、删除接口数据权限控制原生数据权限仅对列表查询生效详情、修改、删除接口默认无过滤会出现「看不到列表但能通过ID编辑别人数据」的越权漏洞。解决方案在 Service 层统一校验数据权限通过工具类判断当前用户是否有权操作该条数据无权限直接抛出异常。// 校验当前用户是否拥有该数据操作权限 DataScopeUtils.checkDataPermission(bizGoods.getCreateBy(), bizGoods.getDeptId());6.2 超级管理员数据权限放行框架默认超级管理员自动放行所有数据权限无需手动处理自定义拦截器需保留该逻辑避免管理员数据被过滤。6.3 多角色数据权限冲突解决用户拥有多个角色时遵循最大权限原则全部权限 自定义 部门及以下 部门 本人。七、数据权限高频Bug与避坑指南坑1新增数据后自己看不到原因业务表未自动填充 dept_id、create_by 字段解决严格使用框架自带的自动填充规则勿手动insert字段为空坑2数据权限不生效原因1Mapper查询方法未加 DataScope 注解原因2测试账号为超级管理员默认全量数据原因3角色数据权限配置为「全部数据」坑3关联查询、多表查询数据权限失效原因原生拦截器仅针对单表字段过滤解决多表查询手动拼接数据权限条件或自定义拦截器适配关联表坑4分页总数与列表数据不一致原因分页count查询未走数据权限拦截解决保证count查询和list查询均被数据权限拦截坑5导出数据越权原因导出接口未添加数据权限注解解决导出 Mapper 方法统一添加 DataScope八、生产级最佳实践总结所有业务表必带 dept_id、create_by这是数据权限的基石所有业务列表查询必加 DataScope统一开启数据过滤单表查询优先使用原生规则不重复造轮子特殊维度使用自定义注解AOP拓展坚决不改源码增删改详情接口必须手动权限校验杜绝越权漏洞导出、批量操作接口优先适配数据权限保障数据安全。九、下篇预告下一篇为系列第三篇RuoYi 第三方功能集成实战OSS文件上传、短信验证码、微信登录、支付对接全程无坑、可直接复制上线的生产级集成方案。