学习笔记018——若依框架数据权限功能的实现
ps:本文所使用的若依是前后端分离的v3.6.0版本。
1、建表
建立业务表的时候,需要在表中添加user_id和dept_id两个字段。(字段一定要一样,下文能体现)
user_id:表中该条记录的创建人id
dept_id:表中该条记录的创建人的部门id
建表SQL:
CREATE TABLE `t_warehouse_info` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',`dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',`warehouse_code` varchar(255) DEFAULT NULL COMMENT '地址编码',`sort` bigint(20) DEFAULT '1' COMMENT '排序',`video_original_name` varchar(500) DEFAULT NULL COMMENT '源视频名',`video_name` varchar(500) DEFAULT NULL COMMENT '视频名字',`video_url` varchar(500) DEFAULT NULL COMMENT '视频具体地址',`original_file_name` varchar(500) DEFAULT NULL COMMENT '源文件名(图片、pdf)',`file_name` varchar(500) DEFAULT NULL COMMENT '文件名(图片、pdf)',`file_url` varchar(500) DEFAULT NULL COMMENT '文件具体地址(图片、pdf)',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`update_time` datetime DEFAULT NULL COMMENT '更新时间',`remark` varchar(500) DEFAULT NULL COMMENT '备注',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='整体库房介绍';
2、生成代码
本地运行若依管理平台,打开代码生成页面。
点击导入表
选择导入刚刚创建的业务表
点击生成代码
3、设置用户权限
例如本人用超级用户给自己创建了一个用户,用户角色的信息如下:
本人的角色权限是部门及以下的权限
4、代码修改
生成的代码我们是不能直接使用的。需要做一些修改。
首先在controller类的插入记录接口中,为实体类插入用户id和部门id
其次在xml文件中,为select的sql添加 表别名 和 ${params.dataScope}
最后在service的实现类的列表查询方法上添加 注解
@DataScope(deptAlias = "d", userAlias = "d")
注意发现:
deptAlias = "d", userAlias = "d"
中的d就是表的别名。
5、原理分析
ctrl+左键点击我们发现他是一个自定义注解
在数据切面类中,获取了当前用户信息,并且将注解中的表别名一并传入了dataScopeFilter方法中。
我们在点击进入到dataScopeFilter方法中。
瞬间明白了,通过if判断当前用户的权限范围,配合注解中的表别名,生成不同权限的sql语句。
最后将sql放到业务实体类继承的BaseEntity类的params字段中。
xml文件中的${params.dataScope}就是对应了BaseEntity类中的params字段。
/**** @param joinPoint 切点* @param user 当前用户* @param deptAlias 部门表别名* @param userAlias 用户表别名*/
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
{StringBuilder sqlString = new StringBuilder();for (SysRole role : user.getRoles()){// 获取当前用户的数据权限范围String dataScope = role.getDataScope();if (DATA_SCOPE_ALL.equals(dataScope)){/** 全部数据权限 1 */sqlString = new StringBuilder();break;}else if (DATA_SCOPE_CUSTOM.equals(dataScope)){/** 自定数据权限 2 */sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,role.getRoleId()));}else if (DATA_SCOPE_DEPT.equals(dataScope)){/** 部门数据权限 3 */sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));}else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)){/** 部门及以下数据权限 4 */sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",deptAlias, user.getDeptId(), user.getDeptId()));}else if (DATA_SCOPE_SELF.equals(dataScope)){if (StringUtils.isNotBlank(userAlias)){/** 仅本人数据权限 5 */sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));}else{// 数据权限为仅本人且没有userAlias别名不查询任何数据sqlString.append(" OR 1=0 ");}}}if (StringUtils.isNotBlank(sqlString.toString())){Object params = joinPoint.getArgs()[0];if (StringUtils.isNotNull(params) && params instanceof BaseEntity){BaseEntity baseEntity = (BaseEntity) params;baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");}}
}
这里权限范围值是存在了dataScope字段中。
通过dataScope字段对比
/*** 全部数据权限*/public static final String DATA_SCOPE_ALL = "1";/*** 自定数据权限*/public static final String DATA_SCOPE_CUSTOM = "2";/*** 部门数据权限*/public static final String DATA_SCOPE_DEPT = "3";/*** 部门及以下数据权限*/public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";/*** 仅本人数据权限*/public static final String DATA_SCOPE_SELF = "5";/*** 数据权限过滤关键字*/public static final String DATA_SCOPE = "dataScope";
例如本人的权限范围是:本部门及以下的权限。则生成的sql语句是:
OR u.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {当前登录用户部门id} or find_in_set( {当前登录用户部门id} , ancestors ) )
最后存在BaseEntity类的params字段中。
/*** Entity基类** @author ruoyi*/
public class BaseEntity implements Serializable {private static final long serialVersionUID = 1L;/** 搜索值 */private String searchValue;/** 创建者 */private String createBy;/** 创建时间 */@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@Excel(name = "时间", dateFormat = "yyyy-MM-dd HH:mm:ss",sort = 100,width = 28)private Date createTime;/** 更新者 */private String updateBy;/** 更新时间 */@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date updateTime;/** 备注 */private String remark;/** 请求参数 */private Map<String, Object> params;}
6、最终请求执行的SQL 语句
14:59:24.942 [http-nio-8080-exec-21] DEBUG c.r.c.m.W.selectWarehouseInfoList - [debug,137] - ==> Preparing: select id, user_id, dept_id, warehouse_code, sort, video_original_name, video_name, video_url, original_file_name, file_name, file_url, create_time, update_time, remark from t_warehouse_info d WHERE (d.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = 204 or find_in_set( 204 , ancestors ) )) order by sort# 提取Sql
select id, user_id, dept_id, warehouse_code, sort, video_original_name, video_name, video_url, original_file_name, file_name, file_url, create_time, update_time, remark from t_warehouse_info d WHERE (d.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = 204 or find_in_set( 204 , ancestors ) )) order by sort