设计|算法
权限设计
大概有这几种模式:
用户+组+角色+权限
用户+组+权限
用户+角色+权限
用户+权限
最近看了别人的设计方法,大多以“整数”来表示权限值,如添加、浏览、删除和修改,分别用1、2、4、8这几个整数来代替,不过,各人的做法有所不同,举例如下:
1.用2的n次幂组成权限值的集合,如1、2、4、8、16...,某用户的权限值为其子集中的整数之和,如 7=1+2+4,5=1+4。如果要从数据库检索包含某几种权限的用户,则先把这几种权限值相加,假设和为k,然后select * from table where 1 and 用户权限值 = 'k';如果要判断某用户有哪些权限,则取出其权限值k,分别用k&1,K&2,K&4,k&16...,如果为真,则表示有值等于“&”右边整数的权限,例如,如果k&4为真,则此用户有权限表中值等于4的权限;
2.用质数2、3、5、7、11...组成权限集合,某用户的权限为其子集中各整数的乘积,如 210 = 2*3*5*7,我觉得这种方法很有趣,难点在于如何分解质因数;但我有些不认同原作者的提法,他认为权限之间可能存在包含关系,如某用户有删除权限,则其一定有浏览权限,要不然就没法删除,事实确实是这样,不过我认为这样太复杂了,容易出错,我觉得权限最好是“原子”的,互不干扰,也就是说某用户有删除权限而没浏览权限则其无法进行删除操作,因为他看不到东西,解决这个矛盾的关键是在给用户赋权时,把浏览权限也赋给他;
3.不用整数,而是用“向量表”方法(也许我说的不一定对),把所有可能的权限按一定的顺序排列,如添加、浏览、修改、删除...,用户的权限值为固定100位长度的字符串,如100010100001....01,从左起每一位对应一种操作权限,如果有这种权限,则此位的值为1,反之,则为0,作者之所以把用户权限值固定为100位,我想是考虑到升级问题,但我认为这还不够科学,我认为用户的权限值长度应小于权限个数,举例如下:
权限排列表:添加、浏览、修改、删除,用户A有添加和浏览的的权限,则其权限值为11,用户B有浏览和修改的权限则其权限值为011,用户C有浏览和删除的权限则其权限值为0101,这样设计的好处为:当权限表中增加别的权限时,不会影响用户表或角色表;
4.我曾经的做法,在后台管理中把权限分为两大类:栏目权限和操作权限,每个栏目对应一个目录,操作权限细分为浏览、添加、修改和删除,用户进入系统后首先判断有没有栏目权限,然后判断有没有操作权限,判断栏目权限相对简单一些,首先获取访问页面的路径path,然后分解出目录,对应用户拥有的目录权限,如果此目录包含在用户有权管理的目录数组中(从数据库取出),则其有进入此目录的权限,否则,没有,然而,在判断操作权限好象有些麻烦,但突然想到添加、浏览、修改和删除与我的文件命名规则是基本是对应的,但有点不同的是,我把添加和删除的功能合并在一个文件中了,例如文件名为proAddEdit.php,幸好意识到修改文件时多了个传递参数id,于是,我用正则解决了这个问题,今天看来,这种方法似乎过时了,因为不适应面向对象的思想和用框架体系来开发系统!
以上是个人粗浅的认识和描述,若有错误,请各位指正,希望高人给些意见!
Posted by: trooman 2005-12-28 16:02
咋个这么冷清,一个发表点意见的都没有?
Posted by: axgle 2005-12-28 16:05
已收藏。
Posted by: Donyad 2005-12-28 16:41
1 2 3 的思想是相同的,只是实现上的手法不同而已
而3后半部分楼主的例子,恕偶愚笨,看不懂
3的做法是很C的,driver级别或者系统级别的程序很常用
比如*nix下的文件权限0755 0777之类
方法1 跟 方法3 原型是一模一样的,就是二进制位,方法3 是对这个的一个字符串模拟
二进制 十进制
100 4
+ 1 1
------------
101 5
用相互独立的位来标志权限,就是为了原子性,素数同样具有这个特性
所以派生出2的做法,而分解质因数,我并不认为这个会是一个问题,因为三种方法都需要去检查所需要的权限
既然是检查,除一下所需要的质数即可
而3里面所说的要变长的问题
1和2正好在概念上回避了这个问题
实际上,在C里面用二进制,有个对齐的问题,就是要8位8位的申请,8位8位的用,无所谓太长了浪费
只是象方法3这样用字符串来模拟二进制时会有浪费
而方法1 2在真正保存时,也是保存成一个int,也是一个申请过来就那么多位的二进制空间,无所谓浪费
扩展和弹性上,方法1和方法2是没有影响的
对方法3来说是个问题,那是因为方法3模拟得不好... 方法3感觉有猪鼻子插葱之嫌
--------------
敲code多了,文字表达能力可能不行了,偶说不对的或说不清的地方欢迎大家拍砖,3q
Posted by: lihun21 2005-12-28 19:27
做个记号先
学习一下
现在还没有用到这么深的权限系统
我现在只有三种权限的用户,所以还没有考虑那么多
超级管理员->普通管理员->普通用户
我想,我用的是这种模式
用户+权限
Posted by: wwccss 2005-12-28 20:06
楼主的文章不错。Donyad兄分析的也很有水平。
Posted by: cozo 2005-12-28 20:10
这种东西只要一种方法就可以了。
我就只使用第一种。
Posted by: bitQ 2005-12-28 21:47
这个方法我有看到过~~~
用二进制表示权限,不会互相影响,期待做个涉及到这个的项目
高手就是高手~~`
Posted by: BinzyWu 2005-12-28 22:01
具体怎么标记权限 这个较无所谓
一般的系统
RBAC是已经够用的.
一般Access Controller有3种
user based
group based
role based
RBAC有成熟的理论基础, 你可以搜索以下, 能搜到很多论文.
但如果不是一般的应用系统, 那么权限系统可能设计需要较为特别. 这里只有普遍理论, 未必有普遍方法.
Posted by: terpomo 2005-12-29 00:31
学习了
Posted by: bleakwind 2005-12-29 01:14
我比较落后,我是将每个人的权限组成的数组序列化放入数据库。。。
每次载入页面初始化出来。。。
Posted by: nameless 2005-12-29 08:51
见过一个用方法3做的权限判断,操作很方便,也很灵活
栏目权限用的直接把栏目标识用界定符分隔连接,操作时判断有没有这个标识,简单,对栏目数过多且操作员过多的时候这个数据库效率应该不高(如果操作员能超过 10W 的话),呵呵
Posted by: trooman 2005-12-29 11:18
QUOTE (nameless 2005-12-29 08:51)
见过一个用方法3做的权限判断,操作很方便,也很灵活
栏目权限用的直接把栏目标识用界定符分隔连接,操作时判断有没有这个标识,简单,对栏目数过多且操作员过多的时候这个数据库效率应该不高(如果操作员能超过 10W 的话),呵呵
是的,我也认为方法3不会比二进制的效率差,在具体使用时可以用like,str_replace等,还可以模拟二进制。
那种所谓的“栏目”权限管理,现在已经过时了,但思想还是可以沿用的,如“对应栏目”改成“对应模块”,但实现方式已经截然不同了!
Posted by: sean.zhuo 2005-12-29 13:51
哪位大哥能給我講解一下"角色"這個概念嗎?不懂什麽叫角色.
Posted by: KnightE 2005-12-29 14:50
1和3,本质还是一样的吧。
1有个好处,节省空间。LZ提到开100个权限用来升级。不过我遇到过一个超过100个权限类别的系统,而且用户树较多。所以后来压成了16进制存储(原来还是一样),就类似1的处理方法了。
不过3最大的好处应该在于直观(其实如果权限项很多的话,也不直观了,呵呵)。
个人认为“权限储存和判断的方法”其实还不是“权限设计”的重点和难点。我们还需要考虑其他东西。比如权限的设计结构(RBAC/GBAC/UBAC)的选择,比如权限在应用系统中的使用……
我GBAC(基于组的权限控制)用的比较多。一般的逻辑是:
组成树型结构,用户跟组结点
判断权限,从组根目录开始往用户所在组进行遍历。起始权限为“禁止”
遍历时,子组权限覆盖起始权限,直至用户。
最后用户权限覆盖起始权限。得到最终权限码。
虽然貌似有些繁杂,不过较灵活些。
其次谈谈权限的使用。通常的做法(至少我是这么做的),即在“所需”时,根据以上逻辑判断某用户相对某权限“是否通过”,例如(乱写的,只是想表示是在需要是进行判断):
CODE
// when someone posts a new topic
if ($access_controller->check($user, 'post'))
{
// access passed
$user->post($content);
}
else
{
// access denied
$sys->accessDenied();
}
而我一直很想尝试的,是这样一种权限使用方法:即在$user实例出来时,已经装配好他拥有的权限(check once, run anywhere),例如:
CODE
class User
{
var $sid;
var $name;
var $passwd;
var $email;
// ...
function __call()
{
// it must be a ACCESS DENIED process here
die('no permission');
}
// maybe no other methods here...
}
// we need overload the User class in PHP4
// for the __call magic method
overload('User');
$user = new User();
// we need a AccessInject method to inject accesses into user object
$access_controller->access_inject($user)
// then, the user object includes its access methods...
// ok, we use the user's method directly
$user->post($content);
// if the user object includes the post method, it has the right permission...
随便写了点,没有很仔细考虑结构和命名,希望能表达清楚我的意思。
抛砖引玉……
Posted by: LuciferStar 2005-12-29 17:40
做过一个表单,用法1和3保存多选的表单数据。
Posted by: james.liu 2006-01-05 17:10
如果是面向对象的,,倾向于小K的想法
用户登陆时,,如果用户名,密码,什么都对的,允许他登陆时,,实例化用户信息,包括权限
Posted by: gudai 2006-01-11 16:06
权限设计。头疼的问题。
来源:http://club.phpe.net/index.php?act=Print&client=printer&f=2&t=11828