jeecg数据权限实现原理

表结构分析

jeecg框架的数据权限规则保存在t_s_data_rule表,该表主要字段如下:

字段名称 字段类型 字段描述
id varchar(96) id编号
rule_name varchar(96) 规则名称
rule_column varchar(300) 规则字段
rule_conditions varchar(300) 规则条件
rule_value varchar(300) 规则值
functionId varchar(96) 所属功能的id

rule_name 是用来展示规则的时候方便识别的, rule_column 对应要查询的数据的列字段名称, rule_conditions 是作用于 rule_column 的条件(>, <, like, =, 等等), rule_value 是 rule_column 列字段对应的值,functionId 是用来关联到具体功能或接口的标识。有了这几个字段数据,我们就可以构造出 where 条件,拼接在 sql 语句上,从而实现通过权限授权管理使得不同的用户在同一个功能上可以看到不同的数据。

拼接 SQL 的代码分析

jeecg框架用 CriteriaQuery 类封装了 Hibernate 的QBC查询方法,通过 HqlGenerateUtil 工具类组装 CriteriaQuery 对象或拼装 sql 语句。HqlGenerateUtil.getDataAuthorConditionHql( ) 方法先从 request 对象的属性中得到当前功能对应的数据规则,然后比对数据规则与要查询的对象模型的字段名称是否匹配,如果匹配则根据对象模型的字段类型,把 rule_value 转换成对应的类型拼接在 CriteriaQuery 对象上。


    /**
     * 获取装载数据权限条件的HQL
     * @return cq
     * @param cq
     * @param searchObj
     */
    public static CriteriaQuery getDataAuthorConditionHql(CriteriaQuery cq, Object searchObj) {
        Map ruleMap = getRuleMap();
        PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(searchObj);
        String aliasName, name, type;
        for (int i = 0; i < origDescriptors.length; i++) {
            aliasName = origDescriptors[i].getName();
            name = origDescriptors[i].getName();
            type = origDescriptors[i].getPropertyType().toString();
            try {
                if (judgedIsUselessField(name) || !PropertyUtils.isReadable(searchObj, name)) {
                    continue;
                }
                // 如果规则包含这个属性
                if (ruleMap.containsKey(aliasName)) {
                    addRuleToCriteria(ruleMap.get(aliasName), aliasName, origDescriptors[i].getPropertyType(), cq);
                }

                Object value = PropertyUtils.getSimpleProperty(searchObj, name);
                // 根据类型分类处理
                if (type.contains("class java.lang") || type.contains("class java.math")) {

                    // for:查询拼装的替换
                    if (value != null && !value.equals("")) {
                        HqlRuleEnum rule = PageValueConvertRuleEnum.convert(value);
                        value = PageValueConvertRuleEnum.replaceValue(rule, value);
                        ObjectParseUtil.addCriteria(cq, aliasName, rule, value);
                    }

                    // for:查询拼装的替换
                } else if ("class java.util.Date".equals(type)) {
                    QueryTimeFormat format = origDescriptors[i].getReadMethod().getAnnotation(QueryTimeFormat.class);
                    SimpleDateFormat userDefined = null;
                    if (format != null) {
                        userDefined = new SimpleDateFormat(format.format());
                    }
                    if (isNotEmpty(value)) {
                        cq.eq(aliasName, value);
                    }
                } else if (!StringUtil.isJavaClass(origDescriptors[i].getPropertyType())) {
                    Object param = PropertyUtils.getSimpleProperty(searchObj, name);
                    if (isHaveRuleData(ruleMap, aliasName) || (isNotEmpty(param) && itIsNotAllEmpty(param))) {
                        // 如果是实体类,创建别名,继续创建查询条件

                        // for:用户反馈
                        cq.createAlias(aliasName, aliasName.replaceAll("\\.", "_"));

                        getDataAuthorConditionHql(cq, param);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return cq;
    }

根据jeecg框架提供的文档《JEECG 平台权限开发手册V3.7.2.pdf》,框架还提供了 miniDao 拼接 SQL 的方式来实现数据权限,基本实现原理与前面对表结构的分析原理差不多,大家可参考文档在 demo 项目中体验一下数据权限的用法,再看一下代码最终生成的查询 sql ,基本上就能掌握数据权限的实现原理了。

关于数据权限的一些思考

在我接触过的多个管理后台框架中,实现数据权限的思路基本与上文分析的差不多,制定规则然后拼接 sql ,有的框架会要求开发建表的时候,必须包含固定的字段,该字段与人员基本信息字段相关联,这样检查用户的权限的时候直接就获得了关联关系;而有的框架做得更灵活一些,可以配置字段的别名并映射到另一张表的某个字段上。jeecg 框架在数据权限方面做得比较完整了,既有简单易用的 Hibernate 查询条件封装,也有灵活可控的 miniDao 纯 sql 拼接,还支持自定义 sql 的规则配置。

当然,数据权限设计应该根据业务出发,只要能满足业务需要即可,不用追求功能齐全而过度设计,导致代码逻辑过于复杂,反而不好维护和传承。

你可能感兴趣的:(jeecg数据权限实现原理)