问题引出
最近,许多学员反馈项目中需要处理数据权限,但是不知道怎么处理比较合适。这篇文章将针对这个问题,给出一种比较通用且容易扩展的数据权限设计方案。
现状
目前流行的权限框架已经有支持数据权限的了,但是需要配置在接口和方法上,扩展性不是很好,那么怎样做能让扩展性最大化呢?
很容易想到的就是:将数据权限的控制放到数据库里存储,在权限拦截时先判断接口是否有权访问,在接口有权访问后,接下来根据配置的条件判断是否有权使用指定的参数值。(做的更高级些,可以对返回的结果进行检查,包含了某个值的某个对象不允许访问的话,也当做无权访问处理,这篇手记里暂时不考虑这个情况)。
那么,具体怎么做呢?
数据库设计
先从数据库表设计说起,首先定义一个数据权限控制表结构:
具体介绍一下每个字段含义:
主键 id;
acl_id 映射权限点表主键,代表每行记录是针对哪个权限点的;
status 代表当前这条配置是否有效,方便临时激活与禁用;
param 代表需要校验的参数名,允许一个请求有多个参数参与数据校验;如果参数复杂,比如包含对象,定义的参数可能为a.b.c 这种多级的形式,建议不要太复杂
operation 代表数据拦截的规则,使用数字代表是等于、大于、小于、大于等于、小于等于、包含、介于之间等,可以根据自己需要增加或减少支持的拦截规则
value1 和 value2 用来和param、operation组成一个关系表达式,比如:1
next_param_op 字段根据需要使用,如果一个权限点支持多条数据规则时,连接两个规则之间的操作, 还是 &&
seq 字段用于某个权限点包含多条数据权限规则时的顺序
假设有这么一条数据,那么他的含义是:id为1(acl_id)的权限点,配置了一条有效(status=1)的数据规则,规则是:传入参数id(param)的值要大于(operation)10(value1)
数据权限校验逻辑
有了表结构后,接下来就是增加接口能对数据进行更新和获取了,然后有个页面能对其进行展示和新增操作了,这里就不占更多篇幅了,重点说一下逻辑的处理。
权限课程里原生实现一套权限管理( 课程地址:https://coding.imooc.com/class/149.html )部分已经对权限点做的基本管理和权限拦截就不在这里重复说了,具体看视频和代码就可以了,这里重点说一下如何在已有的权限上进行数据权限的扩展。首先给出url拦截核心代码和权限校验的核心代码(单独看这段代码不去看课程的细节应该也能看懂个大概):
从代码的 处,可以拿到实际要判断的权限点。在判断某个指定的权限点已经有权限访问时,代码的 、处,需要加入数据权限的校验。
既然要校验参数了,那么就需要把参数传入 hasUrlAcl 这个方法。doFilter方法里的 Map requestMap = request.getParameterMap(); 的requestMap就是url的参数列表,这种方式对于某些特殊的post提交不是完全适用,比如通过body里传递json格式的参数。实际项目中怎么把参数传递到方法里,可以根据项目接口的实际定义来处理。
当hasUrlAcl拿到参数且判断指定的权限点有权访问时,去sys_acl_data表根据acl_id查询出有效的规则列表,逐条判断,这里注意许多细节的处理:
1、单条规则的解读
2、多条规则间的逻辑与和或,
3、参数带层级时的解读(a.b.c这种),实际中可以根据项目中接口的定义规范来决定处理的复杂度。
这个实现后,当url有权访问时,没有数据规则或者数据规则校验通过时,这个url才算真正的有权访问。
这时,肯定有人会问,我的接口是这样定义的 /a/.json 这种的该如何做数据权限拦截呢?其实这种方式的接口,课程里目前稍微调整一下也可以支持,调整如下:
注释的内容是开启正则匹配的,就是通过正则去匹配url,这里使用 url is not null and url != '' and # REGEXP url 代替 url = # ,然后在配置每个权限点时使用正则去配置每个权限点的url就可以了,比如刚才url配置权限校验时可以配置成 /a/[56].json。当然这种方式对权限管理员的正则表达式有一定的要求。这时,在取符合条件的url时校验不过的权限点就取不出来了。取不出来不能直接就当做有处理,可以考虑遇到这种的再配置一个通配(/a/*.json)的权限,每次匹配到这种通配的url时必须保证匹配一个包含正则的校验才算有权限就可以了。这个的细节可以自己做一些不同的处理,这里只提供一个大概的思路。
结尾
关于数据权限就先说到这里,个人认为上面的方式在扩展性方面会相对好一些,实现起来难度也不是很大,如有问题欢迎指出。
其他权限文章参考
领取专属 10元无门槛券
私享最新 技术干货