RuoYi升级Mybaits-plus后数据权限不生效处理办法

1,Mybaits-plus Config

@AutoConfigureAfter(PageHelperAutoConfiguration.class)
@Configuration
public class MybatisInterceptorAutoConfiguration implements InitializingBean {

    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;

    @Override
    @PostConstruct
    public void afterPropertiesSet() throws Exception {
        //创建自定义mybatis拦截器,添加到chain的最后面
        MybatisDataPermissionIntercept mybatisInterceptor = new MybatisDataPermissionIntercept();
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
            //自己添加
            configuration.addInterceptor(mybatisInterceptor);
        }
    }

}

2,SecurityUtils

在代码中增加方法

    /**
     * 获取当前用的数据权限范围
     *
     * @param userId 用户ID
     * @return 结果
     */
    public static String getUserDataScope()
    {
        return getLoginUser().getUser().getRoles().get(0).getDataScope();
    }

    protected static final ThreadLocal<String> threadLocal = new ThreadLocal();
    /**
     * 设置权限标识
     */
    public static void startDataScope(String ...dataScope){
        threadLocal.set(Arrays.toString(dataScope));
    }
    /**
     * 获取权限标识
     */
    public static String getDataScope(){
        return threadLocal.get();
    }
    /**
     * 清除权限标识
     */
    public static void cleanDataScope(){
        threadLocal.remove();
    }

3,数据权限处理

@Intercepts(
        {
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        }
)
@Slf4j
public class MybatisDataPermissionIntercept implements Interceptor {
    CCJSqlParserManager parserManager = new CCJSqlParserManager();

    /**
     * 全部数据权限
     */
    public static final String DATA_SCOPE_ALL = "1";

    /**
     * 自定数据权限
     */
    public static final String DATA_SCOPE_CUSTOM = "2";

    /**
     * 车型数据权限
     */
    public static final String DATA_SCOPE_VEHICLE_CONFIGURE = "3";

    /**
     * 车系及以下数据权限
     */
    public static final String DATA_SCOPE_VEHICLE_MODEL_AND_CHILD = "4";

    /**
     * 仅本人数据权限
     */
    public static final String DATA_SCOPE_SELF = "5";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        try {
            Object[] args = invocation.getArgs();
            MappedStatement ms = (MappedStatement) args[0];
            Object parameter = args[1];
            RowBounds rowBounds = (RowBounds) args[2];
            ResultHandler resultHandler = (ResultHandler) args[3];
            Executor executor = (Executor) invocation.getTarget();
            CacheKey cacheKey;
            BoundSql boundSql;
            //由于逻辑关系,只会进入一次
            if (args.length == 4) {
                //4 个参数时
                boundSql = ms.getBoundSql(parameter);
                cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
            } else {
                //6 个参数时
                cacheKey = (CacheKey) args[4];
                boundSql = (BoundSql) args[5];
            }
            String sql = boundSql.getSql();
            log.info("原始SQL: {}", sql);
            //判断线程内是否有权限信息
            String dataScopes = SecurityUtils.getDataScope();
            if (dataScopes!= null && dataScopes.contains("dataScope")){
                // 增强sql
                Select select = (Select) parserManager.parse(new StringReader(sql));
                SelectBody selectBody = select.getSelectBody();
                if (selectBody instanceof PlainSelect) {
                    this.setWhere((PlainSelect) selectBody,dataScopes);
                } else if (selectBody instanceof SetOperationList) {
                    SetOperationList setOperationList = (SetOperationList) selectBody;
                    List<SelectBody> selectBodyList = setOperationList.getSelects();
                    selectBodyList.forEach((s) -> {
                        this.setWhere((PlainSelect) s,dataScopes);
                    });
                }
                String dataPermissionSql = select.toString();
                log.info("增强SQL: {}", dataPermissionSql);
                BoundSql dataPermissionBoundSql = new BoundSql(ms.getConfiguration(), dataPermissionSql, boundSql.getParameterMappings(), parameter);
                return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, dataPermissionBoundSql);
            }
            //注:下面的方法可以根据自己的逻辑调用多次,在分页插件中,count 和 page 各调用了一次
            return executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
        } finally {
            //清除线程中权限参数
            SecurityUtils.cleanDataScope();
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }

    protected void setWhere(PlainSelect plainSelect,String dataScopes) {
        Expression sqlSegment = this.getSqlSegment(plainSelect.getWhere(),dataScopes);
        if (null != sqlSegment) {
            plainSelect.setWhere(sqlSegment);
        }
    }

    @SneakyThrows
    public Expression getSqlSegment(Expression where,String dataScopes) {
        //用户信息是在gateway中去获取的,获取完之后直接存入到header中,然后再调用过程中传递header
        //getLoginUser 是获取用户信息,在header中去获取
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null){
            return where;
        }
        SysUser user = loginUser.getUser();
        StringBuilder sqlString = new StringBuilder();
        sqlString = getStringBuilder(user,sqlString,dataScopes);
        if (StringUtils.isNotBlank(sqlString.toString())) {
            if (where == null){
                where = new HexValue(" 1 = 1 ");
            }
            sqlString.insert(0," AND (");
            sqlString.append(")");
            sqlString.delete(7, 9);
            //判断是不是分页, 分页完成之后 清除权限标识
            return CCJSqlParserUtil.parseCondExpression(where + sqlString.toString());
        }else {
            return where;
        }
    }


    private static StringBuilder getStringBuilder(SysUser user, StringBuilder sqlString,String dataScopes) {
        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(
                        " OR {}.id IN ( SELECT vehicle_configure_id FROM sys_role_vehicle_configure WHERE role_id = {} ) ", DataScopeConstants.DATA_SCOPE_VEHICLE_ALIAS,
                        role.getRoleId()));
                if(dataScopes.contains(DataScopeConstants.DATA_SCOPE_USER)){
                    sqlString.append(StringUtils.format(" AND {}.user_id = {} ", DataScopeConstants.DATA_SCOPE_USER_ALIAS, user.getUserId()));
                }
            }
            else if (DATA_SCOPE_VEHICLE_CONFIGURE.equals(dataScope))
            {
                sqlString.append(StringUtils.format(" OR {}.vehicle_configure_id = {} ", DataScopeConstants.DATA_SCOPE_VEHICLE_ALIAS, user.getVehicleConfigureId()));
            }
            else if (DATA_SCOPE_VEHICLE_MODEL_AND_CHILD.equals(dataScope))
            {
                sqlString.append(StringUtils.format(
                        " OR {}.id IN ( SELECT id FROM vehicle_configure WHERE vehicle_model_id = {} )",
                        DataScopeConstants.DATA_SCOPE_VEHICLE_ALIAS, user.getVehicleModelId()));
            }
            else if (DATA_SCOPE_SELF.equals(dataScope))
            {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(DataScopeConstants.DATA_SCOPE_USER))
                {
                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", DataScopeConstants.DATA_SCOPE_USER_ALIAS, user.getUserId()));
                }
                else
                {
                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
                    sqlString.append(" OR 1=0 ");
                }
            }
        }
        return sqlString;
    }
}

StringBuilder 方法就是若依的实现,此次更改同时整合了mybatis-plus-join

下面看实际使用过程:
1,在查询前调用start方法

SecurityUtils.startDataScope(DataScopeConstants.DATA_SCOPE_VEHICLE);

在这里插入图片描述这里的leftjoin要定义好别名,与StringBuilder 里面的一致,不然对应不上数据权限

文笔不好,有什么疑问可以联系我, VX:liuhui_plus

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值