在企业管理系统中,经常有这样的要求:
1. 用户通常只能查看本身部门的数据
2. 能够设置用户能够查看哪些部门的数据
这种权限的控制,通常称为数据权限,与之对应的功能权限,则是系统中哪些功能能够使用——①菜单、按钮等元素能正常显示;②若是用户访问了自己不可见的功能,系统也能阻止(访问控制)。 node
开发时间长了,就发现编程通常就是两个问题:
1. 在哪里设置(数据从哪里来)
2. 在哪里使用(数据到哪里去)
好比工做流引擎,设置,即在界面上拖画流程图,并保存为特定的xml数据;使用,即流程引擎解读xml数据,使其正确的按照用户的意图执行程序。
数据权限的问题,一样能够分红这两个问题来处理。 mysql
设置的问题:
在用户设置界面,设置用户的管辖权限 sql
作到这样的设置界面,并不困难。 数据库
在这里,主要要解决的一个问题是,如何把这种关系存储下来
常规方案:使用关联表[用户ID,组织ID]
但是发现,一旦组织机构数量多了之后(如省市县乡,通常一个省就有1000个乡/街道以上),再加上用户数量多了之后——每每是组织机构节点越多,则用户也越多。理论上,这个关联表的数据量将到达千万级(仅理论上,由于对于绝大多数用户来讲,仅能访问本部门数据)。 编程
创新方案:组织机构使用code作主键,而且在用户表中新建字段为“已受权的组织(authorized_orgs)”,直接使用字符串逗号分隔的方式将该关系存起来。
但是立刻会发现,这个字段会很长很长,一个4级的组织,通常须要8位长的代码,若是选中的所有数据,按1000个单位来算,就会有9000长度(含逗号)的字符串。
这里有一个取巧的办法,对于全选了数据,只保存上级单位的code,下级单位就不保存了——由于选中了上级就必然下级所有选上了。 session
该办法要求上下级代码存在一种明显的关系,如上级代码为 0100,下级代码0101。
这个取巧的办法,理论上依然不能规避很长的组织机构代码(如选的所有是叶子节点数据),但在实践中,倒是很好的办法——应该不多出现所有只选叶子节点,而不选父级节点的。
使用zTree(js的树)的代码,能够这样写 oracle
if(zTree==null){ return; } var nodes = zTree.getNodes(); var arr = []; for(var i=0; i<nodes.length; i++){ pushToArray(arr, nodes[i]); } console.log(arr.join(",")); obj.authorizedOrgs = arr.join(","); function pushToArray(arr, node){ if(!node.checked){ return; } if(node.check_Child_State==2||node.check_Child_State==-1){//是节点彻底选上(即不是半选状态)或叶子节点,直接添加 arr.push(node.code); }else if(node.check_Child_State==1){//节点半选状态,递归往下找彻底选中状态的 for(var i=0; i<node.children.length; i++){ pushToArray(arr, node.children[i]); } } }
-----分割线:以上解决怎么设置的问题,如下讨论怎么解决使用的问题-------- sqlserver
数据权限控制的基本思路,通常是会执行的SQL语句中添加where条件,以便限定查出的数据,
如 where 所属机构 in (用户可访问的机构)
而不是在数据查询出来以后,再到代码中进行过滤——由于通常都会对数据进行高效分页,若是已经查询出来数据,再在代码中进行过滤的话,就可能出现一页数据不足一页的状况,数据总数也会与实际页面上查出的数据行不一致。 spa
第一步,在须要进行过滤的表中,要添加一个字段,如org_code,标明每条记录所属的组织机构。
第二步,在查询语句中加入过滤条件。
咱们要加入的SQL语句,大概以下:
where 所属机构 in ('ZZ0101', 'ZZ0102',...)
假如咱们前面存的代码是'ZZ0100,ZZ0201',其中存的是其父级节点'ZZ0100',表明了 'ZZ0101', 'ZZ0102', ...
因此要写成
where ((所属机构 like 'ZZ01%') or (所属机构='ZZ0201'))
拼凑这样的SQL语句估计也是比较麻烦的一件事,有没有简便一点的方法呢?答案是有。
经查,oracle,sqlserver,mysql都是支持正则式查询的。
这样,咱们能够把'ZZ0100,ZZ0201'变成一个正则式,放入条件中进行查询便可!
变成正则式就是 '(^ZZ01.*)|(^ZZ0201)',在mysql使用正则式查询,就是 where 所属机构 RLIKE '(^ZZ01.*)|(^ZZ0201)'
变成正则式以后,也便于放入session中进行存储。
什么,你的数据库支持正则式,orm不支持正则式,那还用orm作什么?code