数据权限说明:不同的用户查看到的数据不一样。比如,部门经理可以查看属于该部门的所有数据,该部门普通员工只能查看属于自己的数据。

数据权限实现思路是:

  1. 角色表中通过data_scope字段来控制数据范围。
  2. data_scope取值说明:1表示全部数据权限。 2表示自定数据权限 。3本部门数据权限 。4本部门及以下数据 权限 。5仅本人数据。
  3. data_scope每一个值对应了不同的sql片段
  4. 用户发起请求,后台获取用户的角色,从角色中读取data_scope字段。
  5. 在service层,Aop处理将sql片段,加入到bean属性map中,key是dataScope,value是sql片段。 这个map的变量名是param。
  6. 在Mapper.xml 通过${params.dataScope},就可以获取到sql片段,进行sql组装。

例子:从用户表中获取用户信息

实体类

public class BaseEntity implements Serializable{private Map<String, Object> params;
}public class SysUser extends BaseEntity{ // 省略
}

Service

@Override
@DataScope(deptAlias = "d", userAlias = "u")
public List<SysUser> selectUserList(SysUser user)
{return userMapper.selectUserList(user);
}

AOP处理

// 处理的是有DataScope注解的方法
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
{// 省略了代码,后面有详细代码。// 通过用户id,获取角色// 通过角色获取data_scope值。// 根据data_scope值,给map中赋值,key是dataScope。value是sql片段。BaseEntity baseEntity = (BaseEntity) params;baseEntity.getParams().put("dataScope", " AND (" + sqlString.substring(4) + ")");}

SysUserMapper.xml

    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user uleft join sys_dept d on u.dept_id = d.dept_idwhere u.del_flag = '0'<!-- 省略了不重要的语句 --><!-- 数据范围过滤 -->${params.dataScope}</select>说明:如果只查询自己的数据。最后的sql片段就是 user_id = 用户id。也就是${params.dataScope}的值。

代码分析

核心逻辑是sql的拼接,使用的是Aop技术实现。

自定义注解类

注解类中的字段是用来拼接sql时,获取表的别名。

/*** 数据权限过滤注解* * @author ruoyi*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope
{/*** 部门表的别名*/public String deptAlias() default "";/*** 用户表的别名*/public String userAlias() default "";
}

切面类DataScopeAspect

切点为自定的注解DataScope, 使用的是前置通知。当方法使用了DataScope注解,在执行该方法前会被拦截。执行DataScopeAspect的doBefore方法。最后调用dataScopeFilter来处理需要拼接的sql。最后把需要拼接的sql存入到BaseEntity对象中。(所有的实体类都继承来了BaseEntity类,这是关键

/*** 数据过滤处理** @author ruoyi*/
@Aspect
@Component
public class DataScopeAspect
{/*** 全部数据权限*/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";// 配置织入点@Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)")public void dataScopePointCut(){}@Before("dataScopePointCut()")public void doBefore(JoinPoint point) throws Throwable{handleDataScope(point);}protected void handleDataScope(final JoinPoint joinPoint){// 获得注解DataScope controllerDataScope = getAnnotationLog(joinPoint);if (controllerDataScope == null){return;}// 获取当前的用户LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());if (StringUtils.isNotNull(loginUser)){SysUser currentUser = loginUser.getUser();// 如果是超级管理员,则不过滤数据if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()){dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),controllerDataScope.userAlias());}}}/*** 数据范围过滤** @param joinPoint 切点* @param user 用户* @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)){sqlString = new StringBuilder();break;}else if (DATA_SCOPE_CUSTOM.equals(dataScope)){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)){sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));}else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)){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)){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) + ")");}}}/*** 是否存在注解,如果存在就获取*/private DataScope getAnnotationLog(JoinPoint joinPoint){Signature signature = joinPoint.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method method = methodSignature.getMethod();if (method != null){return method.getAnnotation(DataScope.class);}return null;}
}

Mapper.xml

通过${params.dataScope}来完成sql的拼接。params是实体类父类中的属性类型,类型为Map。从该属性中可以获取到需要拼接的sql。需要拼接的sql是在切面类中前置方法中存入的。(baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + “)”);)

   <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user uleft join sys_dept d on u.dept_id = d.dept_idwhere u.del_flag = '0'<if test="userName != null and userName != ''">AND u.user_name like concat('%', #{userName}, '%')</if><if test="status != null and status != ''">AND u.status = #{status}
</if><if test="phonenumber != null and phonenumber != ''">AND u.phonenumber like concat('%', #{phonenumber}, '%')</if><if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')</if><if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')</if><if test="deptId != null and deptId != 0">AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))</if><!-- 数据范围过滤 -->${params.dataScope}
</select>

代码中的使用

class: com.ruoyi.system.service.impl.SysUserServiceImpl@Override
@DataScope(deptAlias = "d", userAlias = "u")
public List<SysUser> selectUserList(SysUser user)
{return userMapper.selectUserList(user);
}

权限管理之数据权限(若依框架)相关推荐

  1. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(13)-权限设计

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(13)-权限设计 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2):数据 ...

  2. Yii2.0 后台UI框架以及权限管理扩展实现权限菜单管理

    Yii2.0 后台UI框架以及权限管理扩展实现权限菜单管理 一.安装后台框架ui 二.安装权限管理扩展 三.实现权限菜单管理 一.安装后台框架ui composer require dmstr/yii ...

  3. JAVAWEB开发之权限管理(一)——权限管理详解(权限管理原理以及方案)、不使用权限框架的原始授权方式详解

    知识清单 1.了解基于资源的权限管理方式 2. 掌握权限数据模型 3. 掌握基于url的权限管理(不使用Shiro权限框架的情况下实现权限管理) 4. shiro实现用户认证 5. shiro实现用户 ...

  4. java 二进制 归属权限_【Java EE 学习 75 上】【数据采集系统第七天】【二进制运算实现权限管理】【权限分析和设计】...

    一.权限计算相关分析 1.如何存储权限 首先说一下权限保存的问题,一个系统中最多有多少权限呢?一个大的系统中可能有成百上千个权限需要管理.怎么保存这么多的权限?首先,我们使用一个数字中的一位保存一种权 ...

  5. RBAC权限模型及数据权限扩展的实践

    原文:RBAC权限模型及数据权限扩展的实践 话说大家对RBAC权限模型应该是耳熟能详了.但真正用的好的并不多.并且原始的RBAC模型并不包括数据权限的管理,网上也差点儿没有相关的文章可以參考.本人经过 ...

  6. Android权限管理之Permission权限机制及使用

    前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...

  7. linux查询默认权限命令,Linux权限管理之基本权限

    Linux权限管理之基本权限 1.文件权限: -rw-r--r-- :         r 读   w 写     x 执行 -:   文件类型(- 文件  d 目录  l软链接文件)rw- r-- ...

  8. 【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(8) 权限管理,自定义权限,扩展权限...

    索引 [无私分享:从入门到精通ASP.NET MVC]从0开始,一起搭框架.做项目 目录索引 简述 今天我们来做权限的管理,这篇比较多 希望新手朋友慢慢消化 项目准备 我们用的工具是:VS 2013 ...

  9. mysql 用户管理_mysql 用户管理及数据权限问题总结

    1.远程登录mysql mysql -h ip -u root -p 密码 2.创建用户 格式:grant 权限 on 数据库.* to 用户名@登录主机 identified by "密码 ...

最新文章

  1. IEEE最新薪资报告 | 手机开发者年入153万,机器学习并非最高(附链接)
  2. BZOJ1086 [SCOI2005]王室联邦 【dfs + 贪心】
  3. [2009.08.09]博客园北京俱乐部活动暨《博客园精华集:Web标准之道》现场签售通知...
  4. java pop邮件 源码_[源码和文档分享]基于JavaMail的邮件收发系统
  5. mysql数据库建站教程视频_Mysql数据库零基础到精通视频教程(共6天)
  6. ThinkPHP批量添加数据和getField()示例
  7. Batch Normalization的作用及原理
  8. C# ASP.NET Forms身份认证
  9. 《20170911-构建之法:现代软件工程-阅读笔记》
  10. Codeforces 刷题记录(已停更)
  11. [react] 你有使用过loadable组件吗?它帮我们解决了什么问题?
  12. QThread与QObject的关系
  13. Bigemap如何添加卫星影像在线地图服务
  14. 深度学习笔记~集成方法bagging, boosting和stacking
  15. 前后端分离,不在同一服务器上部署,报错“strict-origin-when-cross-origin”解决
  16. 非手写电子签名的电子合同需注意
  17. Python 毕设精品实战案例——快速索引目录
  18. 在腾讯这一年,坚守初心持续单纯 | 2021年终总结
  19. Talk | 清华大学交叉信息研究院助理教授杜韬:利用计算方法探究流固耦合
  20. 盘点常见的7种网络安全威胁

热门文章

  1. 巧妙设置笔记本让你的聊天语音更加清澈
  2. Revit二次开发01——环境搭建(附Revit 2018 + Visual Studio 2017下载地址)
  3. [译] 编程语言和平台:对一条推特思路的评论
  4. 小学生使用计算机注意,小学生学习电脑编程要注意什么?
  5. 中国著名书法家李云生作品获国内外青睐,长幅作品获拍185万
  6. java静态方法this_在Java的静态方法中可以使用“ this”关键字吗?
  7. 能源动力专业学计算机课程吗,能源与动力工程课程有哪些
  8. 2020济南ICPC J.Tree Constructer(二分图,构造)
  9. python-37-python微服务框架Nameko
  10. win7下安装和使用Windows XP Mode