spring boot 使用 aop技术 实现数据权限过滤

1.aop的概念详解

  • Pointcut:切点,决定处理如权限校验、日志记录等在何处切入业务代码中(即织入切面)。切点分为execution方式和annotation方式。前者可以用路径表达式指定哪些类织入切面,后者可以指定被哪些注解修饰的代码织入切面。
  • Advice:处理,包括处理时机和处理内容。处理内容就是要做什么事,比如校验权限和记录日志。处理时机就是在什么时机执行处理内容,分为前置处理(即业务代码执行前)、后置处理(业务代码执行后)等。
  • Aspect:切面,即PointcutAdvice
  • Joint point:连接点,是程序执行的一个点。例如,一个方法的执行或者一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。
  • Weaving:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。

AOP的体系可以梳理为下图:

2.开始使用aop技术实现数据过滤

数据过滤流程:定义切面和织入点,织入点以注解的形式,注解中定义数据查询表名和数据过滤类别两个参数,在业务查询的service或者controller上添加此注解,并指定参数;然后在切面中实现处理的逻辑,根据表名和过滤类别,编写数据过滤的sql(添加where中的条件实现数据过滤),然后编写的sql以参数的形式写入service或者controller的参数对象中,在mapper中读取sql参数实现数据过滤

概述:通过aop技术,给查询业务的参数对象写入过滤sql,然后在mapper执行时添加此过滤sql实现数据权限过滤。

2.1 定义切面


/**
 * 数据过滤处理
 *
 * @author 
 */
@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";

    /**
     * 数据权限过滤关键字(匹配到mapper中)
     */
    public static final String DATA_SCOPE = "ywjkDataScope";

    // 配置织入点
    @Pointcut("@annotation(com.**.**.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;
        }
        // 获取当前的用户
        try {
            CurrentUser currentUser = ShiroUtils.getSysUser();
            if (currentUser != null) {
                // 如果是超级管理员,则不过滤数据
                if (!currentUser.isAdmin()) {
                    dataScopeFilter(joinPoint, currentUser, controllerDataScope.dataAlias(), controllerDataScope.dataMode());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }

    /**
     * 数据范围过滤
     *
     * @param joinPoint 切点
     * @param user      用户
     * @param dataAlias 数据查询主表的别名
     * @param dataMode  数据过滤类型 0:按照主机过滤,1:按照创建人ID过滤,2:按照创建人账号过滤
     */
    public static void dataScopeFilter(JoinPoint joinPoint, CurrentUser user, String dataAlias, String dataMode) {
        StringBuilder sqlString = new StringBuilder(); // 实现数据过滤的sql
        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)) {
                if ("0".equals(dataMode)) {

                } else if ("1".equals(dataMode)) {

                } else if ("2".equals(dataMode)) {

                } else if ("3".equals(dataMode)) {
                    
                }
            } else if (DATA_SCOPE_DEPT.equals(dataScope)) {
                if ("0".equals(dataMode)) {

                } else if ("1".equals(dataMode)) {

                } else if ("2".equals(dataMode)) {

                } else if ("3".equals(dataMode)) {

                }
            } else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {
                if ("0".equals(dataMode)) {

                } else if ("1".equals(dataMode)) {

                } else if ("2".equals(dataMode)) {

                } else if ("3".equals(dataMode)) {

                }
            } else if (DATA_SCOPE_SELF.equals(dataScope)) {
                if ("0".equals(dataMode)) {
                    
                } else if ("1".equals(dataMode)) {
                   
                } else if ("2".equals(dataMode)) {
                    
                } else if ("3".equals(dataMode)) {
                    
                }
            }
        }
        if (StringUtils.isNotBlank(sqlString.toString())) {
            BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0];
            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;
    }
}

2.2 定义切点



/**
 * 数据权限过滤注解
 *
 * @author 
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
    /**
     * 数据查询主表的别名(无别名默认不填写)
     */
    public String dataAlias() default "";
    /**
     * 数据过滤方式 0:按照主机过滤,1:按照创建人ID过滤,2:按照创建人账号过滤,3:通知消息特殊处理
     */
    public String dataMode() default "0";
}

2.3 需要数据过滤的service或者controller加上注解

@DataScope(dataMode = "1", dataAlias = "ybm")
    @Override
    public List<YwglBusinessMonitorVo> selectBusinessMonitorList(YwglBusinessMonitor ywglBusinessMonitor) {
        return ywglBusinessMonitorMapper.selectBusinessMonitorList(ywglBusinessMonitor);
    }

2.4 mapper适配参数

<select id="***" parameterType="**.**"
            resultMap="**">
        <include refid="**Vo"/>
        <where>
            <if test="id != null ">and id = #{id}</if>
            <!-- 数据范围过滤 -->
            ${params.DataScope}
        </where>
    </select>

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值