数据权限 数据权限和菜单权限不一样
菜单权限:
根据不同的性质的用户,显示不同的菜单。
数据权限:此代码的数据权限是基于若依框架,基于部门权限的简单数据权限设置。
设置权限,不同的用户只能访问本用户的数据,或者本部门的数据。当然对于特殊的领导可以跨部门访问数据。这些都是可以设置权限。
实现功能 【若依框架|基于若依框架的数据权限。】本系统针对多个幼儿园,不同的幼儿园园长,只能增删查改属于本幼儿园的儿童信息。但是所有的儿童信息都储存在同一个表中。此时就需要对不同的幼儿园园长设置数据权限。
实现步骤
- 在设置儿童信息表时,添加一个字段部门id(dept_id bigint 20) ,这将作为数据过滤的条件。
文章图片
- 在MyBaits中的Mapper文件中的select语句中添加(数据过滤范围)
id="selectKinChildrenInfoVo">
select U.CHILDREN_ID, U.CHILDREN_NAME, U.SEX, BIRTHDAY, U.REGION_CODE, U.HOME_ADDRESS, U.NATION_ID, U.PARENT_NAME, U.PARENT_PHONE ,U.dept_id from kin_children_info U
id="selectKinChildrenInfoList" parameterType="KinChildrenInfo" resultMap="KinChildrenInfoResult">
${params.dataScope}
and CHILDREN_NAME like concat('%', #{childrenName}, '%')
and SEX = #{SEX}
and BIRTHDAY = #{BIRTHDAY}
and REGION_CODE = #{regionCode}
and HOME_ADDRESS = #{homeAddress}
and NATION_ID = #{nationId}
and PARENT_NAME like concat('%', #{parentName}, '%')
and PARENT_PHONE = #{parentPhone}
- 在service层添加注解 (@DataScope)
/**
* 查询儿童信息列表
* U是儿童信息表的别名
* @param kinChildrenInfo 儿童信息
* @return 儿童信息
*
*/
@Override
@DataScope(deptAlias = "U")
public List selectKinChildrenInfoList(KinChildrenInfo kinChildrenInfo)
{
return kinChildrenInfoMapper.selectKinChildrenInfoList(kinChildrenInfo);
}
解释 上述了过后已经实现了我需要的,基于部门的数据权限访问。
当然,这不能帮助我们弄清楚,具体的实现机制。
解释注解 @DataScope(deptAlias=“U”) 这就需要我们去看若依框架中DataScopeAspect.java这个类(用来进行数据过滤处理的 基于切面编程)
package com.ruoyi.framework.aspectj;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.system.domain.SysRole;
import com.ruoyi.system.domain.SysUser;
/**
* 数据过滤处理
*
* @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;
}
// 获取当前的用户
SysUser currentUser = ShiroUtils.getSysUser();
if (currentUser != null)
{
// 如果是超级管理员,则不过滤数据
if (!currentUser.isAdmin())
{
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
controllerDataScope.userAlias());
}
}
}/**
* 数据范围过滤
*
* @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))
{
sqlString = new StringBuilder();
break;
}
//判断数据权限是否为自定数据权限
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{
sqlString.append(StringUtils.format(
" AND ({}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} )) ", deptAlias,
role.getRoleId()));
}
//判断数据权限是否为部门权限,我所需要的
else if (DATA_SCOPE_DEPT.equals(dataScope))
{
//将DataScope注解里表别名,用户的部门id代替占位符 编程字符串
sqlString.append(StringUtils.format(" WHERE {}.dept_id = {} ", deptAlias, user.getDeptId()));
}
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{
sqlString.append(StringUtils.format(
" AND ({}.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(" AND ({}.user_id = {} )", userAlias, user.getUserId()));
}
else
{
// 数据权限为仅本人且没有userAlias别名不查询任何数据
sqlString.append(" AND (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,从第一位开始
//用于MyBaits文件中${params.dataScope}附加SQL语句
baseEntity.getParams().put(DATA_SCOPE,sqlString.substring(1) );
}
}
}/**
* 是否存在注解,如果存在就获取
*/
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;
}
}
当然如果想附加不同的SQL语句,就需要对上述dataScopeFilter函数进行修改。
PS:
对于开发者而言,多看源码,看懂源码,方便我们更好的去改代码,去实现功能。
推荐阅读
- 若依源码学习笔记|若依源码学习4(AOP实现数据权限控制)
- spring|雷神《谷粒商城》spring-cloud-alibaba(阿里巴巴网关)gateway3.0.4,配置问题
- springBoot|SpringBoot整合Spring Security+JWT实现前后端分离登录权限处理
- Authing|如何使用 Authing 单点登录,集成 Discourse 论坛()
- 产品功能|单点登录的三种实现方式
- 面试官问(Java 序列化和反序列化为什么要实现 Serializable 接口(什么鬼??))
- 【面经】被虐了之后,我翻烂了equals源码,总结如下
- 人工智能|高手云集、丰富活动,斩获佳绩,超过2万名开发者参与的AI社团邀你加入!
- 人工智能|AVH部署实践 (一) | 在Arm虚拟硬件上部署飞桨模型