基于Nutz.Dao的数据权限管理的实现1
相关文章索引请点击这里
上一篇文章已经理清了大概的思路,本篇文章就介绍一下具体的实现。
数据库设计:
新增几张表,分别是数据权限、数据资源、权限和资源关系、权限和角色关系、权限和人员关系。
数据资源最主要的字段是:
QueryName:查询语句的名称。
PartName:查询语句条件部分的名称。
SQL语句的组成:
- /*按数据规则读取人员*/
- /*userDao.getUsersCountByRule*/
- SELECT count(*) FROM (SELECT * FROM v_info_user a
- WHERE (1<>1
- #if (part_user_company!false){
- or EXISTS (SELECT * FROM v_info_user b WHERE b.companyid=a.companyid AND b.id=@byuserid)
- #}
- #if (part_user_all!false){
- or 1=1
- #}
- )) a $condition
userDao.getUsersCountByRule:对应数据资源表中的QueryName。
part_user_company和part_user_all:对应数据资源表中的PartName。
格式化SQL的类:
这是关键的一个类,在期望使用权限控制时调用,它会根据传入的SQL语句名称和当前人员ID格式化一个最终的SQL,这个SQL会根据不同的人员所具备的权限使用不同的条件集合。它的实现如下:
- package com.xnck.mfpms.dao;
- import com.xnck.mfpms.entity.QueryPart;
- import org.beetl.core.Configuration;
- import org.beetl.core.GroupTemplate;
- import org.beetl.core.Template;
- import org.beetl.core.resource.StringTemplateResourceLoader;
- import org.nutz.dao.Dao;
- import org.nutz.dao.Sqls;
- import org.nutz.dao.entity.Entity;
- import org.nutz.dao.sql.Sql;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- public class SqlTool {
- /**
- * 自定义GroupTemplate
- */
- private static GroupTemplate gt;
- /**
- * 拦截并按照数据规则创造新的SQL
- * @param dao
- * @param sqlName
- * @param curUserId
- * @return
- */
- public static Sql injectSearchSql(Dao dao, String sqlName, String curUserId){
- Map<String, Object> map = getActiveQueryParts(dao, sqlName, curUserId);
- Sql sql = dao.sqls().create(sqlName);
- String oldSQL = sql.getSourceSql();
- Template template = gt().getTemplate(oldSQL);
- template.binding(map);
- String newSQL = template.render().replace('\t', ' ').replace('\r', ' ').replace('\n', ' ').trim();;
- sql.setSourceSql(newSQL);
- return sql;
- }
- /**
- * 获得人员可以使用的SQL语句的条件部分
- * @param dao
- * @param queryName
- * @param curUserId
- * @return
- */
- private static Map<String, Object> getActiveQueryParts(Dao dao, String queryName, String curUserId){
- List<QueryPart> roleParts = getQueryPartsFromSql(dao, "injectDao.getQueryPartByRole", queryName, curUserId);
- List<QueryPart> userParts = getQueryPartsFromSql(dao, "injectDao.getQueryPartByUser", queryName, curUserId);
- Map<String, Object> map = new HashMap<String, Object>();
- for (QueryPart queryPart : roleParts){
- map.put(queryPart.getPartname(), true);
- }
- for (QueryPart queryPart : userParts){
- if (!map.containsKey(queryPart.getPartname())){
- map.put(queryPart.getPartname(), true);
- }
- }
- return map;
- }
- private static List<QueryPart> getQueryPartsFromSql(Dao dao, String sqlName, String queryName, String curUserId){
- Sql sql = dao.sqls().create(sqlName);
- sql.params().set("userId", curUserId).set("queryName", queryName);
- sql.setCallback(Sqls.callback.entities());
- Entity<QueryPart> entity = dao.getEntity(QueryPart.class);
- sql.setEntity(entity);
- dao.execute(sql);
- return sql.getList(QueryPart.class);
- }
- /**
- * 获取GroupTemplate
- *
- * @return GroupTemplate实例,如果没有自定义,就生成一个默认的
- */
- public static GroupTemplate gt() {
- if (gt == null) {
- StringTemplateResourceLoader resourceLoader = new StringTemplateResourceLoader();
- Configuration cfg;
- try {
- cfg = Configuration.defaultConfiguration();
- cfg.setStatementStart("#");
- cfg.setStatementEnd(null);
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- gt = new GroupTemplate(resourceLoader, cfg);
- }
- return gt;
- }
- }
injectDao.getQueryPartByRole:查询该人员对应的角色能够访问的PartName集合。
injectDao.getQueryPartByUser:查询该人员能够访问的PartName集合。
当有了PartName集合后,使用模板引擎格式化指定的SQL语句,在上面给出的示例语句就可以变成一个完整的SQL语句,也就实现了数据权限的控制。
最终使用:
在DAO层的某个查询函数中,使用上面的类,得到我们需要的数据集合。
- /**
- * 按条件获得用户总数量(数据规则限制)
- * @param byUserId 用来当做条件的用户ID
- * @param cnd 输入的查询条件
- * @return
- */
- public int getUsersCountByRule(String byUserId, Condition cnd){
- Sql sql = SqlTool.injectSearchSql(this.dao, "userDao.getUsersCountByRule", byUserId);
- sql.setParam("byuserid", byUserId);
- sql.setCondition(cnd);
- return this.searchCount(sql);
- }
以上就是具体的实现,但是这样实现只是初步实现而已,至少还有两个问题解决的不太完美:
第一,这里必须是工程师主动调用,在真正的项目开发时,很有可能被遗漏。而且对于DAO层来说封装度不够,代码显得很开放,很丑陋。
第二,只考虑到了查询方面的控制,而增删改没有顾及,不知道具体应用时是否会碰到问题。
至于第一点,我在最近又修改了一个版本,我觉的已经封装的够彻底了,会在之后的文章放出;至于第二点,我还需要项目的检验和使用,才能总结出比较好的解决办法。
楼主,你在nutz qq群里吗?
至于第一点,我在最近又修改了一个版本,我觉的已经封装的够彻底了,会在之后的文章放出; 请问这个放出来了吗?
还有如果用nutz 不用sql查询 直接使用cnd 查询,如:dao.queryt(Test.class,Cnd.where(“a”,”=”,23)
这种效果如何进行数据权限管理
我在QQ群里;新的版本我自己已经修改完了,在近期内会写一篇具体的实现;因为并不是在最底层的JDBC实现的,所以要实现数据权限过滤,用create sql好点,如果非要使用这种方式的话,可以用我新的版本的方式来实现,自己封装NutDao,改变原始的逻辑,不过我觉的有点麻烦。