数据权限就是决定让某些人看到某个范围的数据,比如管理员看到所有学生成绩,学生本人看到自己的成绩。
我们写业务sql 的时候容易忽略到数据权限的问题,因此把他做成aop加上注解 的形式,自动在我们写的sql后面拼接一下新的过滤条件,来起到自动过滤的作用。
过滤条件可以是id in (....) 或者 是 (select * from * ....)
实现思路是,写一个注解类,用来传值,写一个aop切面类,读取注解的值。然后从数据库中取出当前用户相关权限,用string拼接sql。
将拼接的sql存入查询的主体类的某个字段中,在写sql的xml文件里面用 ${变量} 来替换拼接好的sql,形成新的sql。
具体代码:
先写一个注解类
package com.guyue.common.datascope.annontation;
import java.lang.annotation.*;
/**
* 数据权限过滤注解
*
* @author ruoyi
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope
{
/**
* 部门表的别名
*/
public String deptAlias() default "";
/**
* 用户表的别名
*/
public String userAlias() default "";
/**
* 区域表别名
*
* @return
*/
public String areaAlias() default "";
/**
* 公司表别名
*
* @return
*/
public String companyAlias() default "";
}
写一个切面类
package com.guyue.common.datascope.aspect;
import com.guyue.common.core.base.BaseEntity;
import com.guyue.common.datascope.annontation.DataScope;
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 java.lang.reflect.Method;
/**
* 数据过滤处理
*
* @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.guyue.common.datascope.annontation.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;
}
// 获取当前的用户
// 如果是超级管理员,则不过滤数据
dataScopeFilter(joinPoint, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), controllerDataScope.areaAlias(), controllerDataScope.companyAlias());
}
/**
* 数据范围过滤
*
* @param joinPoint 切点
* @param deptAlias 部门别名
* @param userAlias 用户别名
*/
public static void dataScopeFilter(JoinPoint joinPoint, String deptAlias, String userAlias, String areaAlias, String companyAlias)
{
StringBuilder sqlString = new StringBuilder();
sqlString.append("id = 1");
//获取方法传入的参数
Object params = joinPoint.getArgs()[0];
BaseEntity baseEntity = (BaseEntity) params;
baseEntity.getParams().put(DATA_SCOPE, sqlString);
}
/**
* 是否存在注解,如果存在就获取
*/
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;
}
}
使用注解类
@Override
@DataScope(deptAlias = "111")
public List<SysUser> listUsers(SysUser sysUser) {
val sysUsers = sysUserMapper.listUsers(sysUser);
System.out.println(sysUsers.toString());
return null;
}
对应的pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
注意,启动类上面要扫描到aop所在的包,不然aop无法生效
<select id="listUsers" resultMap="BaseResultMap" parameterType="com.guyue.sysuser.entity.SysUser">
select *
from sys_user
where
${params.dataScope}
</select>