Spring Boot中使用注解的方式实现数据权限控制

3522 篇文章 107 订阅

在业务开发过程中,经常会碰到需要查询某个人所在部门的数据或者某个人所在部门相关子部门的数据等需要做数据权限的场景,这里结合若依开发平台描述下如何实现数据权限的控制。

原理:

通过自定义注解的方式在查询数据之前查询配置的权限标记(如:当前部门数据权限等),拼接出相应的sql作为变量传递给Mapper层进行关联查询

1、定义数据权限注解

import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;
/** * 数据权限过滤注解 * */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface DataScope{/**     * 部门表的别名     */    public String deptAlias() default "";
/**     * 用户表的别名     */    public String userAlias() default "";
/**     * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来     */    public String permission() default "";}

2、定义注解切面处理逻辑

/** * 数据过滤处理 * * */@Aspect@Componentpublic 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";
    @Before("@annotation(controllerDataScope)")    public voiddoBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable{clearDataScope(point);handleDataScope(point, controllerDataScope);}
    protected voidhandleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope){ // 获取当前的用户        LoginUser loginUser = SecurityUtils.getLoginUser();if(StringUtils.isNotNull(loginUser)){            SysUser currentUser = loginUser.getUser(); // 如果是超级管理员,则不过滤数据if(StringUtils.isNotNull(currentUser)&& !currentUser.isAdmin()){                String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),                        controllerDataScope.userAlias(), permission);}}}
/**     * 数据范围过滤     *     * @param joinPoint 切点     * @param user 用户     * @param deptAlias 部门别名     * @param userAlias 用户别名     * @param permission 权限字符     */    public static voiddataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission){        StringBuilder sqlString = newStringBuilder();        List<String> conditions = new ArrayList<String>();
for(SysRole role : user.getRoles()){            String dataScope = role.getDataScope();if(!DATA_SCOPE_CUSTOM.equals(dataScope)&& conditions.contains(dataScope)){                continue;}if(StringUtils.isNotEmpty(permission)&& StringUtils.isNotEmpty(role.getPermissions())&& !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))){                continue;}if(DATA_SCOPE_ALL.equals(dataScope)){                sqlString = newStringBuilder();                conditions.add(dataScope);                break;}elseif(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()));}elseif(DATA_SCOPE_DEPT.equals(dataScope)){                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));}elseif(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()));}elseif(DATA_SCOPE_SELF.equals(dataScope)){if(StringUtils.isNotBlank(userAlias)){                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));}else{ // 数据权限为仅本人且没有userAlias别名不查询任何数据                    sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));}}            conditions.add(dataScope);}
 // 多角色情况下,所有角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据if(StringUtils.isEmpty(conditions)){            sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));}
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) + ")");}}}
/**     * 拼接权限sql前先清空params.dataScope参数防止注入     */    private voidclearDataScope(final JoinPoint joinPoint){        Object params = joinPoint.getArgs()[0];if(StringUtils.isNotNull(params)&& params instanceof BaseEntity){            BaseEntity baseEntity = (BaseEntity) params;            baseEntity.getParams().put(DATA_SCOPE, "");}}}

3、在service层使用

/**     * 根据条件分页查询用户列表     *     * @param user 用户信息     * @return 用户信息集合信息     */    @Override    @DataScope(deptAlias = "d", userAlias = "u")    public List<SysUser>selectUserList(SysUser user){return userMapper.selectUserList(user);}

需要注意的是,注解中使用的表别名应与mapper定义的别名一致,否则sql无法运行

4、在Mapper中映射使用

<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.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 u    left join sys_dept d on u.dept_id = d.dept_id    where u.del_flag = '0'    <!-- 数据范围过滤 -->    ${params.dataScope}</select>

以上就是通过注解方式实现数据权限控制的方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值