Easy.Admin 的权限管理
- 本篇介绍 Easy.Admin 使用的权限管理功能的原理以及使用
- 项目地址 https://github.com/xxred/Easy.Admin
原理
-
本着先实现再完善优化的原则,就不新造轮子了,而是直接使用 NewLife.XCode自带的权限管理功能,下面详细介绍
-
从代码层面来讲,就是记录一个角色与一个控制器和控制器所有方法的关系。举个例子,管理员角色拥有用户控制器中添加用户、删除用户等方法的访问权限。假设一个控制器对应一个菜单,控制器的方法就是菜单的操作,这里用户菜单的 id 设为 1,添加用户这个操作标记为 1,删除用户操作标记为 2,更新用户操作标记为 4,依次类推标记所有操作为 2 的 n 次方
-
当然用什么标记可以自己定,这里只是让他们组成的列表符合位域的设计,即 2 的幂(即 1、2、4、8 等)。记录方式实际上就是将用户 id(这里设管理员 id 为 1)、菜单 id、操作标记、是否授权等这个几个属性记为一条数据。每次访问的时候,就根据当前用户和访问的菜单和操作,查询是否有授权,即可实现权限管理功能
-
比如,管理员角色对于用户菜单的添加、删除、更新操作,具有权限访问,这些数据记录为
角色 id 菜单 id 操作 id 是否授权 1 1 1 是 1 1 2 是 1 1 4 是 -
当使用位域的方式记录所有操作时,比如同时授权添加、删除、更新这三个操作,那么就是
1+2+4 = 7
,二进制即001 + 010 + 100 = 111
,也即1|2|4 = 7
,每添加一个操作,直接用当前记录值和操作标记进行或运算。因为每个操作标记对应的二进制都是只有一个 1,而且位置不同,所以加起来不会产生进位,结果相当于累加(没有进位)。那么上述表记录变成角色 id 菜单 id 操作 id 1 1 7 -
那么怎么知道哪个操作被授权了呢?哪个位置上是 1 就说明哪个操作被授权。而判断方法就是与运算,需要判断的操作和记录值进行与运算,两个位置都是 1 的,结果对应位置才是 1,其余位置都是 0。比如,判断删除操作是否被授权,2 对应二进制 10,和记录值 7 的二进制 111 进行与运算,结果得 010。但如果,10 不在记录值里面,即 101,那么与运算结果为 0。
2 & 7 = 2 -> 10 & 111 = 10
,10 & 101 = 0
-
总的来说就是,添加操作就是或运算,判断操作就是与运算,那去掉操作呢?那也简单,实际上直接减去就行,对应的二进制运算叫做异或,也叫半加运算,没有进位的加法。比如
111 ⊕ 10
,10 加上去之后没有进位,结果是 101,相当于去掉了操作,大部分高级语言用的异或符号是^
使用
- 上面原理说起来也简单,说白了就是两个二进制操作,使用位域把记录简化。后来实际应用的时候,就将一个角色的所有菜单的操作权限全部合在一起,作为角色的一个字段,这个字段的值类似于
1#255,2#255,3#255,4#255
。设这个字段为Permission
,逗号分隔每个菜单,每个记录是菜单id#操作记录值
。上述值就是 1-4 这个几个菜单的操作值,都是 255,即1|2|4|8|16|32|64|128
,默认可容纳 8 个操作 - 那么如何将控制器与菜单和操作关联起来呢? NewLife.XCode还提供了扫描控制器的代码,使用时通过在方法添加特性(注解)标记这个方法,代码就会通过反射将每个控制器生成一个菜单,方法生成对应菜单的操作,并记录标记值
- 权限判断的时候,也是通过这个特性(注解)获取当前方法的操作标记值,找到对应的菜单,再比较操作值
- 代码详见:
总结
- 对于一些复杂的权限设计,或者比较精细,那么自己写代码实现才是最好的选择,通用的权限设计毕竟只是满足大众需求
- 实用至上为原则,只要能很好解决你的问题,那它就是好的解决方案
共同学习,写下你的评论
评论加载中...
作者其他优质文章