A-A+

基于Nutz.Dao的数据权限管理的实现1

2016年05月17日 技术, 默认 评论 2 条 阅读 3,554 次

相关文章索引请点击这里

上一篇文章已经理清了大概的思路,本篇文章就介绍一下具体的实现。

数据库设计:

新增几张表,分别是数据权限、数据资源、权限和资源关系、权限和角色关系、权限和人员关系。

数据资源最主要的字段是:

QueryName:查询语句的名称。

PartName:查询语句条件部分的名称。

SQL语句的组成:

  1. /*按数据规则读取人员*/
  2. /*userDao.getUsersCountByRule*/
  3. SELECT count(*) FROM (SELECT * FROM v_info_user a
  4. WHERE (1<>1
  5. #if (part_user_company!false){
  6. or EXISTS (SELECT * FROM v_info_user b WHERE b.companyid=a.companyid AND b.id=@byuserid)
  7. #}
  8. #if (part_user_all!false){
  9. or 1=1
  10. #}
  11. )) a $condition

userDao.getUsersCountByRule:对应数据资源表中的QueryName。

part_user_company和part_user_all:对应数据资源表中的PartName。

格式化SQL的类:

这是关键的一个类,在期望使用权限控制时调用,它会根据传入的SQL语句名称和当前人员ID格式化一个最终的SQL,这个SQL会根据不同的人员所具备的权限使用不同的条件集合。它的实现如下:

  1. package com.xnck.mfpms.dao;
  2. import com.xnck.mfpms.entity.QueryPart;
  3. import org.beetl.core.Configuration;
  4. import org.beetl.core.GroupTemplate;
  5. import org.beetl.core.Template;
  6. import org.beetl.core.resource.StringTemplateResourceLoader;
  7. import org.nutz.dao.Dao;
  8. import org.nutz.dao.Sqls;
  9. import org.nutz.dao.entity.Entity;
  10. import org.nutz.dao.sql.Sql;
  11. import java.io.IOException;
  12. import java.util.HashMap;
  13. import java.util.List;
  14. import java.util.Map;
  15. public class SqlTool {
  16.     /**
  17.      * 自定义GroupTemplate
  18.      */
  19.     private static GroupTemplate gt;
  20.     /**
  21.      * 拦截并按照数据规则创造新的SQL
  22.      * @param dao
  23.      * @param sqlName
  24.      * @param curUserId
  25.      * @return
  26.      */
  27.     public static Sql injectSearchSql(Dao dao, String sqlName, String curUserId){
  28.         Map<String, Object> map = getActiveQueryParts(dao, sqlName, curUserId);
  29.         Sql sql = dao.sqls().create(sqlName);
  30.         String oldSQL = sql.getSourceSql();
  31.         Template template = gt().getTemplate(oldSQL);
  32.         template.binding(map);
  33.         String newSQL = template.render().replace('\t', ' ').replace('\r', ' ').replace('\n', ' ').trim();;
  34.         sql.setSourceSql(newSQL);
  35.         return sql;
  36.     }
  37.     /**
  38.      * 获得人员可以使用的SQL语句的条件部分
  39.      * @param dao
  40.      * @param queryName
  41.      * @param curUserId
  42.      * @return
  43.      */
  44.     private static Map<String, Object> getActiveQueryParts(Dao dao, String queryName, String curUserId){
  45.         List<QueryPart> roleParts = getQueryPartsFromSql(dao, "injectDao.getQueryPartByRole", queryName, curUserId);
  46.         List<QueryPart> userParts = getQueryPartsFromSql(dao, "injectDao.getQueryPartByUser", queryName, curUserId);
  47.         Map<String, Object> map = new HashMap<String, Object>();
  48.         for (QueryPart queryPart : roleParts){
  49.             map.put(queryPart.getPartname(), true);
  50.         }
  51.         for (QueryPart queryPart : userParts){
  52.             if (!map.containsKey(queryPart.getPartname())){
  53.                 map.put(queryPart.getPartname(), true);
  54.             }
  55.         }
  56.         return map;
  57.     }
  58.     private static List<QueryPart> getQueryPartsFromSql(Dao dao, String sqlName, String queryName, String curUserId){
  59.         Sql sql = dao.sqls().create(sqlName);
  60.         sql.params().set("userId", curUserId).set("queryName", queryName);
  61.         sql.setCallback(Sqls.callback.entities());
  62.         Entity<QueryPart> entity = dao.getEntity(QueryPart.class);
  63.         sql.setEntity(entity);
  64.         dao.execute(sql);
  65.         return sql.getList(QueryPart.class);
  66.     }
  67.     /**
  68.      * 获取GroupTemplate
  69.      *
  70.      * @return GroupTemplate实例,如果没有自定义,就生成一个默认的
  71.      */
  72.     public static GroupTemplate gt() {
  73.         if (gt == null) {
  74.             StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
  75.             Configuration cfg;
  76.             try {
  77.                 cfg = Configuration.defaultConfiguration();
  78.                 cfg.setStatementStart("#");
  79.                 cfg.setStatementEnd(null);
  80.             }
  81.             catch (IOException e) {
  82.                 throw new RuntimeException(e);
  83.             }
  84.             gt = new GroupTemplate(resourceLoader, cfg);
  85.         }
  86.         return gt;
  87.     }
  88. }

injectDao.getQueryPartByRole:查询该人员对应的角色能够访问的PartName集合。

injectDao.getQueryPartByUser:查询该人员能够访问的PartName集合。

当有了PartName集合后,使用模板引擎格式化指定的SQL语句,在上面给出的示例语句就可以变成一个完整的SQL语句,也就实现了数据权限的控制。

最终使用:

在DAO层的某个查询函数中,使用上面的类,得到我们需要的数据集合。

  1. /**
  2.     * 按条件获得用户总数量(数据规则限制)
  3.     * @param byUserId 用来当做条件的用户ID
  4.     * @param cnd 输入的查询条件
  5.     * @return
  6.     */
  7.    public int getUsersCountByRule(String byUserId, Condition cnd){
  8.        Sql sql = SqlTool.injectSearchSql(this.dao, "userDao.getUsersCountByRule", byUserId);
  9.        sql.setParam("byuserid", byUserId);
  10.        sql.setCondition(cnd);
  11.        return this.searchCount(sql);
  12.    }

以上就是具体的实现,但是这样实现只是初步实现而已,至少还有两个问题解决的不太完美:

第一,这里必须是工程师主动调用,在真正的项目开发时,很有可能被遗漏。而且对于DAO层来说封装度不够,代码显得很开放,很丑陋。

第二,只考虑到了查询方面的控制,而增删改没有顾及,不知道具体应用时是否会碰到问题。

至于第一点,我在最近又修改了一个版本,我觉的已经封装的够彻底了,会在之后的文章放出;至于第二点,我还需要项目的检验和使用,才能总结出比较好的解决办法。

2 条留言  访客:0 条  博主:0 条

  1. 鲁鲁

    楼主,你在nutz qq群里吗?
    至于第一点,我在最近又修改了一个版本,我觉的已经封装的够彻底了,会在之后的文章放出; 请问这个放出来了吗?
    还有如果用nutz 不用sql查询 直接使用cnd 查询,如:dao.queryt(Test.class,Cnd.where(“a”,”=”,23)
    这种效果如何进行数据权限管理

    • 哼哼的泰迪熊

      我在QQ群里;新的版本我自己已经修改完了,在近期内会写一篇具体的实现;因为并不是在最底层的JDBC实现的,所以要实现数据权限过滤,用create sql好点,如果非要使用这种方式的话,可以用我新的版本的方式来实现,自己封装NutDao,改变原始的逻辑,不过我觉的有点麻烦。

给我留言

Copyright © 字痕随行 保留所有权利.   Theme  Ality

用户登录

分享到: