数据权限管理
相关文章索引请点击这里
一个完整的权限管理包含系统功能管理和系统数据管理,在工作的前几年一直折腾的是系统功能管理这块,对于系统数据管理很少涉及,一是那个时代还没有那么高的要求,二是通过功能划分把数据管理也间接的做了。随着应用的日渐复杂,客户的要求也越来越高,逐渐的也有些拨开云雾见月明的感觉。
一般来说系统功能管理相对来说更加清晰,也更易于完成,而数据管理相对来说要复杂一些。系统数据管理的解决方案很难有一劳永逸的办法,因为要面对的是底层数据库,甚至是NOSQL这样的数据存储方式,所以更多时候不能一刀切,还是需要具体问题具体分析。
从去年开始接触Nutz.Dao,顿时让我对这款框架爱不释手,让我瞬间就抛弃了Hibernate和Myabatis,相对来说Hibernate太麻烦了,而Myabatis那种xml配置是我极其反感的,估计这都是个人喜好问题。有了好的ORM框架,自然而然的就希望能够有一些固定的手段或者方法能够在一定程度上满足日常的数据管理的开发需要,所以就有了这次试水。
先说说目标:
1. 一定范围内的灵活。不要求非常的灵活,比如不更改一行代码就能完成数据权限的配置,从前端展现到后端数据筛选一劳永逸,我清楚以我目前的情况,很难实现。
2.影响范围要小。如果有一定规模的开发团队,必然具有从低到高的配置,我希望权限管理这块不应该对大多数人造成困扰,我希望只对某些人(比如:专门写Dao层的或者做设计的人员)造成困扰。
3.开发人员友好。不能太过复杂,导致了解和学习的成本太过高昂,一个项目有可能才持续3个月,不可能了解数据管理的实现就要耗费很长时间。
再说说思路:
最开始,为了达到影响范围要小的这个条件,我把目光放到了Service层,开始琢磨着如何使用拦截器和AOP来实现。我的想法是,如果我可以在需要做数据权限管理的函数上加上注解,运行的时候再将标有注解的函数拦截,在执行之前按照人员所分配的权限读取该函数所必须的数据筛选条件,然后将条件再返回给这个函数,最后执行此函数就应该可以解决了。但是在尝试的过程中,我希望被拦截函数的参数是固定的,也就是Controller层调用时,应该传几个参数就传几个参数,这都是有效参数,这样才可以做到影响范围要小。可是,参数固定了,拦截完获得的条件参数就没办法再传递给被拦截的函数了,我尝试了很多办法都没有解决掉这个问题。如果因此而使实现方式变的晦涩难懂,就得不偿失了,于是我陷入了困境,需要尝试其它的解决方案。
在最初的尝试失败之后,我不停的去查阅资料,不停的看其它关于数据管理的博客文章,虽然没有找到我想要的,但是我却明确了一个中心思想,那就是无论什么权限,最终都是落在当前人员上的,最终都是直接或者间接使用人员作为条件去筛选数据的。
在明确了中心思想之后,我想我应该尝试着在筛选数据的时候解决这个问题,于是将目光转到Dao层来实现,新的问题就此出现。如果由人员的权限读取某个SQL所需的筛选条件,那么这些读取出的筛选条件肯定因权限而异,都是动态的。在我遇到的项目中,有时候客户那边已经有库的话,甚至于会让你直接将某表中的数据作为筛选条件,所以经常会出现“select * from table where c1 in (select ss from t where uid=:uid)”这种情况,那么这时候如何将“c1 in (select ss from t where uid=:uid)”视情况拼接到原始SQL后面就是个问题;而且这种支离破碎的拼接语句管理或者配置的时候乱七八糟,非常不利于维护;另一方面,如果我的列也有筛选怎么办,也这样处理,岂不是太乱了;还有就是如果出现了某一个权限使用了其它权限不需要的条件怎么办,比如A权限使用“uid=:uid”,B权限使用“oid=:oid”,赋予参数值的时候要分别处理,很麻烦。
我一度以为只能把这些条件直接存储于数据库中,然后视情况读取出来,再拼接到原始SQL后面,如果在测试的时候出现这样那样的异常,再逐个解决客服,但是总觉的这样的解决办法不明了,让人感到很不舒服。
在这种不舒服的情况下,寻找解决方案的工作一度被搁置,因为天天发愁这个事情饭不思茶不香,有点得不偿失。但是运气来的也是比较快,在逛Nutz社区的时候偶然间看到一篇帖子中提到了模板引擎,然后就去github看了一下示例,突然间感觉这也许是一种实现的方式,如果将语句利用模板引擎格式化,那么在编写的时候就可以看到一个原始SQL的全景,之上提到的大部分问题也能够迎刃而解。同时在一次和朋友喝酒聊天的时候,也提起这件事,坚定了推进下去的信心,于是在不久就做出了原型。
现在实现方式是这样的:
1.所有的需要权限筛选条件参数的Dao层函数必须以“ByRule”关键字结尾,第一个参数必须给“byUserId”,这是为了方便区分和使用,缩小影响的范围,算是代码的规范。
2.Nutz.Dao本身就支持和鼓励将SQL语句集中于一个物理文件中,所以我们可以利用模板引擎和权限提取的条件来格式化SQL语句。
3.在数据库中,我们将结合模板引擎而编写的SQL语句中的条件部分作为资源存储起来,定义为“数据资源”,为了便于将数据权限和功能权限区分,将数据权限定义为“数据规则”。
4.人员关联规则,继而关联资源,按资源使用模板引擎筛出不同的条件部分,进而组合成最终的SQL。
按照以上方式进行构建后,我发现是可行的的,而且在管理的时候,其操作和功能权限部分不会偏离很多。在输入参数不变的情况下,可以在不更改java代码的情况下,只修改SQL文件中的语句即可实现管理。封装一个格式SQL语句的类,这样以“ByRule”结尾的函数内部调用,之后仍旧是Nutz.Dao的实现方式。
在接下来的文章中,我会给出示例代码。另外,tiny框架前阵子也提出了数据管理的思路,他们期望于在JDBC层中做控制,如果可以的话,我也希望能够有所参考。