基于AOP方式实现数据权限的校验

基于AOP方式实现数据权限的校验

本文大纲
一、数据权限注解
二、数据权限AOP
三、数据范围枚举
四、登录用户信息
五、权限相关的工具类
六、AOP数据权限校验基础类
七、AOP数据权限校验基础类

一、数据权限注解

package com.dashu.park.common.annotation;

import com.dashu.park.common.enums.DataScopeType;

import java.lang.annotation.*;

/**
 * 数据权限过滤注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
    /**
     * 是否校验角色,没有角色不然操作
     *
     * @return
     */
    boolean checkRole() default true;

    /**
     * 是否校验数据权限,没有权限,直接返回
     *
     * @return
     */
    boolean checkDataScope() default false;

    /**
     * 数据权限范围的类型,默认是本部门的数据
     *
     * @return
     */
    DataScopeType dataScopeType() default DataScopeType.DATA_SCOPE_DEPT;

}

二、数据权限AOP

package com.dashu.park.common.aspect;


import cn.hutool.core.util.ObjectUtil;
import com.dashu.park.common.annotation.DataScope;
import com.dashu.park.common.bean.DataScopeAopEntity;
import com.dashu.park.common.bean.LoginUser;
import com.dashu.park.common.enums.DataScopeType;
import com.dashu.park.common.exception.BaseException;
import com.dashu.park.common.util.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
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;
import java.util.Optional;

@Aspect
@Component
public class DataScopeAspect {
    /**
     * 配置织入点
     */
    @Pointcut("@annotation(com.dashu.park.common.annotation.DataScope)")
    public void dataScopePointCut() {
    }

    @Before("dataScopePointCut()")
    public void before(JoinPoint point) {
//        handleDataScope(point);
    }


//    protected void handleDataScope(final JoinPoint joinPoint) {
//        // 获得注解
//        DataScope dataScope = getAnnotationLog(joinPoint);
//        if (ObjectUtil.isNull(dataScope)) {
//            return;
//        }
//        // 获取当前的用户
//        LoginUser loginUser = SecurityUtils.getLoginUser();
//
//        // 如果是超级管理员,则不过滤数据
//        if (SecurityUtils.isAdmin(loginUser)) {
//            return;
//        }
//
//        // 1.角色判断
//        if (dataScope.checkRole()) {
//            SecurityUtils.checkRole(loginUser);
//        }
//
//        // 2.权限判断,有权限才执行
//        if (dataScope.checkDataScope()) {
//            // 校验是否有权限
//            SecurityUtils.checkDataScope(loginUser);
//            // 加入查询的规则
//            // 拿到方法的参数,要求第一个参数为实体类且继承 DataScopeAopEntity
//            // 因为要将 DataScopeAopEntity 的属性设置为查询条件
//            Object params = joinPoint.getArgs()[0];
//
//            DataScopeType dataScopeType = dataScope.dataScopeType();
//
//            // 转为权限类型,向上转型
//            DataScopeAopEntity dataScopeAop = (DataScopeAopEntity) params;
//            // 基于数据权限的类型,设置用户的权限值
//            dataScopeType.fillDataScopeType(dataScopeAop, loginUser.getDeptIds());
//        }
//    }


    /**
     * 数据范围过滤
     * <p>
     * 是否存在注解,如果存在就获取
     */
    private DataScope getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        return Optional.ofNullable(method).map(item -> method.getAnnotation(DataScope.class)).orElseGet(() -> null);
    }

    /**
     * 定制一个环绕通知
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Around("dataScopePointCut()")
    public Object advice(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            // 获得注解
            DataScope dataScope = this.getAnnotationLog(joinPoint);
            if (ObjectUtil.isNull(dataScope)) {
                return joinPoint.proceed();
            }
            // 获取当前的用户
            LoginUser loginUser = SecurityUtils.getLoginUser();

            // 如果是超级管理员,则不过滤数据
            if (SecurityUtils.isAdmin(loginUser)) {
                // 执行proceed方法的作用是让目标方法执行
                return joinPoint.proceed();
            }

            // 1.角色判断
            if (dataScope.checkRole()) {
                SecurityUtils.checkRole(loginUser);
            }

            // 2.权限判断,有权限才执行
            if (dataScope.checkDataScope()) {
                // 校验是否有权限
                SecurityUtils.checkDataScope(loginUser);
                // 加入查询的规则
                // 拿到方法的参数,要求第一个参数为实体类且继承 DataScopeAopEntity
                // 因为要将 DataScopeAopEntity 的属性设置为查询条件
                Object params = joinPoint.getArgs()[0];

                DataScopeType dataScopeType = dataScope.dataScopeType();

                // 转为权限类型,向上转型
                DataScopeAopEntity dataScopeAop = (DataScopeAopEntity) params;
                // 基于数据权限的类型,设置用户的权限值
                dataScopeType.fillDataScopeType(dataScopeAop, loginUser.getDeptIds());
            }

            // 执行proceed方法的作用是让目标方法执行
            return joinPoint.proceed();
        } catch (Exception e) {
            return new BaseException(e.getMessage());
        }
    }

}

三、数据范围枚举

package com.dashu.park.common.enums;

import com.dashu.park.common.bean.DataScopeAopEntity;
import lombok.Getter;

import java.util.List;

/**
 * 数据权限的类型
 */
@Getter
public enum DataScopeType {
    /**
     * 基于用户自己的数据权限
     */
    DATA_SCOPE_USER {
        @Override
        public void fillDataScopeType(DataScopeAopEntity dataScopeAop, List<Long> dataScopeIds) {
            dataScopeAop.setUserId(dataScopeIds.get(0));
        }
    },

    /**
     * 基于岗位的数据权限
     */
    DATA_SCOPE_POST {
        @Override
        public void fillDataScopeType(DataScopeAopEntity dataScopeAop, List<Long> dataScopeIds) {
            dataScopeAop.setPostId(dataScopeIds);
        }
    },

    /**
     * 基于部门的数据权限
     */
    DATA_SCOPE_DEPT {
        @Override
        public void fillDataScopeType(DataScopeAopEntity dataScopeAop, List<Long> dataScopeIds) {
            dataScopeAop.setDeptIds(dataScopeIds);
        }
    },

    /**
     * 基于组织,用户组的数据权限
     */
    DATA_SCOPE_ORGANIZATION {
        @Override
        public void fillDataScopeType(DataScopeAopEntity dataScopeAop, List<Long> dataScopeIds) {
            dataScopeAop.setOrganizationIds(dataScopeIds);
        }
    };

    /**
     * 设置数据权限的校验类型
     *
     * @param dataScopeAop 范围类型
     * @param dataScopeIds 范围类型的Id列表
     */
    public abstract void fillDataScopeType(DataScopeAopEntity dataScopeAop, List<Long> dataScopeIds);
}

四、登录用户信息

package com.dashu.park.common.bean;

import com.dashu.park.api.bean.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.List;

/**
 * @author HaiMa
 * @date 2021/6/30
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class LoginUser extends BaseEntity {

    @ApiModelProperty(value = "项目ID")
    private Long pId;

    @ApiModelProperty(value = "用户名ID")
    private Long userId;

    @ApiModelProperty(value = "昵称")
    private String name;

    @ApiModelProperty(value = "用户名")
    private String username;

    @ApiModelProperty(value = "用户角色")
    private List<UserRole> userRoles;

    @ApiModelProperty(value = "登录时间")
    private Long loginTime;

    @ApiModelProperty(value = "场景 WEB(默认)  APP")
    private String scenes;

    @ApiModelProperty(value = "绑定权限ID")
    private List<Long> deptIds;

    @Data
    public static class UserRole {

        @ApiModelProperty(value = "角色ID")
        private Long roleId;

        @ApiModelProperty(value = "角色名")
        private String roleName;

        @ApiModelProperty("场景 WEB(默认)  APP")
        private String scenes;

    }

}

五、权限相关的工具类

package com.dashu.park.common.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.dashu.park.api.response.global.RC_C;
import com.dashu.park.common.bean.BaseDaoByEntity;
import com.dashu.park.common.bean.LoginUser;
import com.dashu.park.common.constants.CommonConstants;
import com.dashu.park.common.exception.BaseException;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;


public class SecurityUtils {

    /**
     * 获取登录的用户信息
     */
    public static LoginUser getLoginUser() {
        HttpServletRequest request = ServletUtils.getRequest();
        if (request == null) {
            throw new BaseException("request 不存在");
        }
        try {
            LoginUser loginUser = (LoginUser) request.getAttribute(CommonConstants.LOGIN_AUTH_USER);
            if (loginUser != null) {
                return loginUser;
            }
            String data = request.getHeader(CommonConstants.LOGIN_AUTH_USER);
            if (StringUtils.isEmpty(data)) {
                throw new BaseException(RC_C.NO_LOGIN);
            }
            data = EncodesUtils.decodeBase64ToStr(data);
            loginUser = JSON.parseObject(data, LoginUser.class);
            if (loginUser == null) {
                throw new BaseException(RC_C.NO_LOGIN);
            }
            request.setAttribute(CommonConstants.LOGIN_AUTH_USER, loginUser);
            return loginUser;
        } catch (Exception e) {
            throw new BaseException(RC_C.NO_LOGIN);
        }
    }

    /**
     * 获取登录的用户信息
     */
    public static LoginUser getLoginUserIgnoreError() {
        try {
            return getLoginUser();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取项目ID
     */
    public static long getProjectId() {
        HttpServletRequest request = ServletUtils.getRequest();
        if (request == null) {
            Long projectId = CommonUtils.getAsynThreadDataProjectId();
            if (projectId != null) {
                return projectId;
            }
            throw new BaseException(RC_C.PROJECT_ERROR);
        }
        try {
//            return EnvUtils.isDev() ? 101 : Long.parseLong(request.getHeader(CommonConstants.PROJECT_ID));
            return Long.parseLong(request.getHeader(CommonConstants.PROJECT_ID));
        } catch (Exception e) {
            throw new BaseException(RC_C.PROJECT_ERROR);
        }
    }

    /**
     * 设置登录信息
     *
     * @param t
     * @param <T>
     */
    public static <T extends BaseDaoByEntity> void fillLoginUser(T t) {
        AssertUtil.isTrue(ObjectUtil.isNull(t), "填充登录用户信息的类不能为空");
        LoginUser loginUser = getLoginUser();
        if (ObjectUtil.isNull(t.getCreateId())) {
            t.setCreateId(loginUser.getUserId());
            t.setUpdateId(loginUser.getUserId());

            t.setCreateName(loginUser.getUsername());
            t.setUpdateName(loginUser.getUsername());
        }
    }

    public static <T extends BaseDaoByEntity> void fillUpdateLoginUser(T t) {
        AssertUtil.isTrue(ObjectUtil.isNull(t), "填充登录用户信息的类不能为空");
        LoginUser loginUser = getLoginUser();
        if (ObjectUtil.isNull(t.getUpdateId())) {
            t.setUpdateId(loginUser.getUserId());
            t.setUpdateName(loginUser.getUsername());
        }

    }

    /**
     * 是否是管理员
     */
    public static boolean isAdmin(LoginUser loginUser) {

        if (StrUtil.isBlank(loginUser.getUsername())) {
            return false;
        }
        return "admin".equals(loginUser.getUsername());
    }

    /**
     * 校验是否有角色
     *
     * @param loginUser
     */
    public static void checkRole(LoginUser loginUser) {
        AssertUtil.isTrue(CollUtil.isEmpty(loginUser.getUserRoles()), "用户没有分配角色");
    }

    /**
     * 校验是否有权限
     *
     * @param loginUser
     */
    public static void checkDataScope(LoginUser loginUser) {
        AssertUtil.isTrue(CollUtil.isEmpty(loginUser.getDeptIds()), "用户没有分配权限");
    }


}

六、AOP数据权限校验基础类

数据权限校验基础类

package com.dashu.park.common.bean;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.util.List;

@Data
@ToString
@EqualsAndHashCode
public class DataScopeAopEntity {
    /**
     * 用户ID
     */
    @ApiModelProperty(value = "用户ID",hidden = true)
    private  Long userId;
    /**
     * 岗位
     */
    @ApiModelProperty(value = "岗位",hidden = true)
    private  List<Long> postId;
    /**
     * 部门Id
     */
    @ApiModelProperty(value = "岗位",hidden = true)
    private  List<Long> deptIds;
    /**
     * 组织Id
     */
    @ApiModelProperty(value = "组织Id",hidden = true)
    private List<Long> organizationIds;

}

数据权限校验入参

package com.interfaces.dept.dto;

import com.dashu.park.common.bean.BasePageDTO;
import com.dashu.park.common.bean.DataScopeAopEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;


/**
 * @author DASHU
 */
@Data
public class DeptPageDto extends DataScopeAopEntity {


    @ApiModelProperty("组织链Id")
    private Long deptLinkId;

    @ApiModelProperty("父级Id")
    private Long parentId;

    @ApiModelProperty("组织名称")
    private String name;

    @ApiModelProperty("表示最大获取级别")
    private Integer maxLevel;


    @ApiModelProperty("级别")
    private Integer level;

    @ApiModelProperty(
            value = "页码,缺省值:1",
            example = "1"
    )
    private int pageNum = 1;

    @ApiModelProperty(
            value = "页数,缺省值:10",
            example = "10"
    )
    private int pageSize = 10;

}

七、使用AOP校验数据权限

    /**
     * 分页获取组织信息
     * @param dto
     * @return
     */
    @ApiOperation(value = "分页获取组织信息")
    @GetMapping("/page")
    @DataScope(checkRole = true,checkDataScope = true,dataScopeType = DataScopeType.DATA_SCOPE_DEPT)
    R<DeptListVo> page(DeptPageDto dto){
        return deptService.page(dto);
    }

参数解析
checkRole = true,//检查角色
checkDataScope = true, //检查数据
dataScopeType = DataScopeType.DATA_SCOPE_DEP //使用部门方式校验

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值