若依数据权限实战:从注解到SQL拼接的完整流程解析

若依数据权限实战:从注解到SQL拼接的完整流程解析
1. 数据权限的本质与业务场景数据权限就像公司里的文件柜——销售部的同事只能打开标着销售部的抽屉财务部只能查看贴着财务标签的文件夹。在若依框架中这种数据隔离机制通过三个核心字段实现user_id标记数据创建者dept_id标记所属部门role_id决定数据可见范围实际项目中遇到过这样的需求某连锁超市系统需要实现区域经理只能查看本区域门店销售数据。我们通过若依的数据权限模块用以下配置就解决了问题DataScope(deptAlias s, userAlias u) public ListSalesData selectSalesList(SalesData sales) { return mapper.selectSalesList(sales); }最终生成的SQL会自动追加条件WHERE s.dept_id IN (1024,1025,1026) -- 该经理管辖的门店ID2. 五层数据权限的配置实战若依将数据权限划分为五个层级就像俄罗斯套娃一样逐层缩小范围权限级别代码标识实际效果适用场景全部数据DATA_SCOPE_ALL无过滤条件系统管理员自定义数据DATA_SCOPE_CUSTOM限定指定部门区域总监本部门数据DATA_SCOPE_DEPT仅当前部门部门经理部门及以下DATA_SCOPE_DEPT_AND_CHILD包含子部门事业部负责人仅本人数据DATA_SCOPE_SELF只看自己创建普通员工配置步骤详解表结构改造给商品表goods添加关键字段ALTER TABLE goods ADD COLUMN dept_id BIGINT COMMENT 部门ID, ADD COLUMN user_id BIGINT COMMENT 用户ID;角色权限配置在系统管理 → 角色管理中设置数据范围用户部门绑定确保用户信息中有正确的dept_id3. 注解与SQL拼接的魔法DataScope注解就像个开关触发AOP切面进行SQL重写。假设我们有如下Mapper查询select idselectGoodsList resultTypeGoods SELECT * FROM goods g WHERE g.status ON_SALE !-- 这里会自动插入数据权限条件 -- ${params.dataScope} /select添加注解后DataScope(deptAlias g, userAlias g) public ListGoods selectGoodsList(Goods goods) { return mapper.selectGoodsList(goods); }实际执行的SQL会变成SELECT * FROM goods g WHERE g.status ON_SALE AND (g.dept_id IN (SELECT dept_id FROM sys_role_dept WHERE role_id 2))4. 避坑指南与性能优化在电商项目实践中我们总结出几个关键点索引优化确保dept_id和user_id字段有索引CREATE INDEX idx_goods_dept ON goods(dept_id); CREATE INDEX idx_goods_user ON goods(user_id);多角色权限合并当用户有多个角色时权限条件会用OR连接AND (g.dept_id IN (101,102) OR g.user_id 10086)特殊场景处理报表导出等需要临时关闭权限过滤DataPermissionHelper.ignore(() - { return exportService.exportFullData(); });缓存策略频繁访问的部门关系数据应缓存Cacheable(value deptTree, key #deptId) public ListLong getChildDeptIds(Long deptId) { // 查询子部门逻辑 }5. 复杂业务场景解决方案遇到跨多表关联查询时可以采用以下模式DataScope(deptAlias {o,s}, userAlias o) public ListOrderVO selectComplexOrderList() { return mapper.selectComplexOrderList(); }对应的XML配置select idselectComplexOrderList resultTypeOrderVO SELECT o.*, s.shop_name FROM orders o LEFT JOIN shops s ON o.shop_id s.id WHERE o.status 1 !-- 会同时生成o和s表的数据权限条件 -- ${params.dataScope} /select曾有个社区团购项目需要实现团长只能查看自己小区的订单我们通过扩展DataScopeAspect增加了小区ID的过滤条件核心修改如下// 在dataScopeFilter方法中追加 if (DATA_SCOPE_COMMUNITY.equals(dataScope)) { sqlString.append( OR {}.community_id {} , alias, user.getCommunityId()); }