官方的权限系统太复杂了,初学者往往云里雾里,搞不清楚。
这是本人的傻瓜版改造。请各位品鉴。
官方的rbac。本人看了诸多文章,虽然最后搞明白了,但是耗费的脑细胞的确不少。而且要数据库支持。用起来实在不便于和自己的系统集成。好坏暂且不论,单从繁琐上而言,的确不算完美。
自己琢磨了一个傻瓜版,简单说一下吧。欢迎拍砖。
权限系统的原理就不详细解说了。总之要点就这几个:
1.用户表,记录具体操作人员账号。
userid
username
2.角色表,或者叫用户组表。记录系统可以使用的角色。
roleid
rolename
funstr(关键)
其中有一个字段:权限串funstr。要用varchar(2000)或更大,是个大字符字段,存储角色的具体权限点信息。下面会解释怎么用。
3.用户角色关联表。把用户和角色关联起来。
再次基础上有无数变形。再此就不在说了,基本就是这三个。
ok,帽子戏法开始:
有看官会问;权限表呢?缺少记录系统权限点的表啊。
这就是傻瓜版的要点,
新建一个类,暂起名fun吧。
其中建一个array,保存系统的所有module的所有class的所有function。
就是系统的所有操作方法。这个array是这样的:
class AdmFunarrAction extends Action
{
/////////////////////////////////////////////////////////////////////////////
/////////////////////////网站所有功能的array/////////////////////////////////
//主键:GROUP-class-function用于权限检查时定位
//值为另一个array,存储具体对应function功能的相关信息
//1.id--权限点对应的字符编码(字母开头,后跟两位字母和数字)
// 是进行权限检查的依据
//2.pid--父权限点对应的字符编码,构造权限树时使用
//3.n--name--权限点名称
//4.t--tree--是否用来构造树节点,存入权限串中
//值1--构造树节点,存入权限串。
//值0--不用构造树节点,不存入权限串,只用来检查,
// 处理几个fun合并用一个id的情况,比如各种查询合并成一个id
//5.l--login--是否需要登录,强行控制,保证安全,0--无需登录 1--必须登录
//6.x--xx--权限点详细说明
//7.p--pic --权限点的树形图标
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//-----总后台所有模块的权限数组
PUBLIC $admfunarr = array(
// 主键 | 标号 |父级标号 |名称 |节点属性| 强制登陆|详细 |图标
'aaaa-0000-0000' =>array('id'=>'a','pid'=>'aaaa', 'n'=>'总后台', 't'=>'1','l'=>'0','x' => '总后台根节点','p'=>'icon-add'),
'Admin-Main-index' =>array('id'=>'a01','pid'=>'a', 'n'=>'后台登陆页', 't'=>'1','l'=>'0','x' => '机构后台管理的登陆页面','p'=>'icon-add'),
'Admin-Main-main' =>array('id'=>'a02','pid'=>'a', 'n'=>'后台首页', 't'=>'1','l'=>'1','x' => '机构后台管理的主页面','p'=>'icon-add'),
'aaaa-0000-0001' =>array('id'=>'a03','pid'=>'a02', 'n'=>'基础设置', 't'=>'1','l'=>'1','x' => '基础设置菜单','p'=>'icon-add'),
'Admin-Adminuser-index' =>array('id'=>'a04','pid'=>'a03', 'n'=>'管理员维护', 't'=>'1','l'=>'1','x' => '管理员维护,包括增删改查','p'=>'icon-add'),
'Admin-Adminuser-getlist' =>array('id'=>'a04','pid'=>'a04', 'n'=>'合-管理员列表', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-getone' =>array('id'=>'a04','pid'=>'a04', 'n'=>'合-管理员单个查询', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-addfun' =>array('id'=>'a04','pid'=>'a04', 'n'=>'合-管理员新增', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-updatefun' =>array('id'=>'a04','pid'=>'a04', 'n'=>'合-管理员修改', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-delfun' =>array('id'=>'a04','pid'=>'a04', 'n'=>'合-管理员删除', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'aaaa-0000-0002' =>array('id'=>'a05','pid'=>'a02', 'n'=>'高级设置', 't'=>'1','l'=>'1','x' => '基础设置菜单','p'=>'icon-add'),
'Admin-Corp-index' =>array('id'=>'a06','pid'=>'a05', 'n'=>'高级管理员维护', 't'=>'1','l'=>'1','x' => '管理员维护,包括增删改查','p'=>'icon-add'),
'Admin-Adminuser-getlist1' =>array('id'=>'a06','pid'=>'a06', 'n'=>'合-管理员列表', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-getone1' =>array('id'=>'a06','pid'=>'a06', 'n'=>'合-管理员单个查询', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-addfun1' =>array('id'=>'a06','pid'=>'a06', 'n'=>'合-管理员新增', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-updatefun1' =>array('id'=>'a06','pid'=>'a06', 'n'=>'合-管理员修改', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
'Admin-Adminuser-delfun1' =>array('id'=>'a06','pid'=>'a06', 'n'=>'合-管理员删除', 't'=>'0','l'=>'1','x' => '总后台管理员管理','p'=>'icon-add'),
);
这是一个复合array,array的每一项也都是一个array。
array的主键是GROUP-class-function三个合成的。别说你不知道这三个的意思啊。
每个主键对应的值也是一个array,描述这个主键对应的function。有这么几个:
//1.id--权限点对应的字符编码,比如a01,a02之类
(字母开头,后跟两位字母和数字,可以重复)
这个是关键啊,
看条件需要时可以重复前面角色表权限字段(funstr)里面保存的就是用逗号分隔的这个funciton编码组合,
代表了这个角色可以拥有的全部操作。 是进行权限检查的依据!
------由于我是用ztree进行权限管理,下面这些附加属性只是为了构造ztree需要的json便于前台分配权限时操作。
除了name(功能的名称)必须,你完全可以忽略不用。但其中仍有精妙之处,请大家耐心。
//2.pid--父权限点对应的字符编码,构造权限树时使用(ztree需要,没什么好说的)
//3.n--name--权限点名称 (没什么好说的。你的function干什么用的总要起个名字吧)
//4.t--tree--是否用来构造树节点,存入权限串中(
这个精妙了)
//值1--构造树节点,存入权限串。
//值0--不用构造树节点,不存入权限串,只用来检查, 处理几个fun合并用一个id的情况,比如一个针对用户的增删改查合并成一个功能点id。
------这什么意思???
我们前面说了,每个function都要在这个数组中有一条记录。但是不是每个function
都代表一个功能点。有的时候权限控制比较粗,比如我只需要控制一个用户管理权限,有这个权限就可以进行用户的增删改查
的全部操作,不需要再细分增删改查这四个操作权限。这时就可以把增删改查的四个权限合并,设置一个虚拟的权限点,比如
上面的 'aaaa-0000-0001',他下面增加增删改查的方法,但是都用同一个编码。
这就是编码重复的条件
这样,再检查权限时,就当做一个权限点进行检查了。一个权限点代表增删改查四个具体操作。
精妙吧.....呵呵呵,无耻!
//5.l--login--是否需要登录,硬编码强行控制,保证安全,即便无意误分派了权限,比如给游客分派了登录才能有的权限,
在这里也可以挡一下。0--无需登录 1--必须登录
//6.x--xx--权限点详细说明 (没什么说了)
//7.p--pic --权限点的树形图标 (没什么说了,ztree需要)
---------------------------------
以上权限array解释完毕,如头晕,请移步草榴开心一下再来
有了这个你的系统的全部function的array,还需要权限点表吗?
而且,维护这样一个array,比维护一个权限点的表,不知道容易了多少倍。
接下来的权限判断就是老生长谈了,无非建一个基类,写一个init方法,你的其他类都从这里继承吧。
<?php
/*
* 总后台公共模块的基础类
*/
class AdminCommonAction extends Action{
/*
* 初始化
* 权限验证
* Session判断
*/
public function _initialize(){
header ( 'Content-Type:text/html;charset=utf-8' );
//是否登录判断,没有登录需要登录
if (!session('?admuserid')){
redirect(__APP__.'/'.GROUP_NAME.'/Login/index');
}
//获得session权限串
$funstr='';
if (session('?admuserfunstr')){
$funstr=session('admuserfunstr');
}
//判断当前访问是否在权限串中
//1.获得权限数组,我的权限数组在一个专门类中,所以要在这里调用一下,也可以写在一起,完全无压力。
$s=new AdmFunarrAction();
$admfunarr=$s->admfunarr;//权限数组
//2.根据group,action,fun获得key
$key=GROUP_NAME.'-'.MODULE_NAME.'-'.ACTION_NAME;//注意加‘-’啊。用‘-’进行连接
if (!array_key_exists("$key",$admfunarr)){
if (! IS_AJAX) {
header ( 'Content-Type:text/html;charset=utf-8' );
echo ('<h2 style="color:red;">失败555...!你可能没有权限啊,快升级吧...</h2>-------------------------<a href="javascript:history.go(-1);">返回</a>');
exit ();
} else {
$json = '{"zt":0,"xx":"失败555...!你可能没有权限啊,快升级吧..."}';
echo $json;
exit ();
}
}
//3.根据key获得id
$id=$admfunarr["$key"]['id'];
//4.根据id判断是否在权限字符串中
$pos = strpos($funstr,$id);
if (!$pos){
if (! IS_AJAX) {
header ( 'Content-Type:text/html;charset=utf-8' );
echo ('<h2 style="color:red;">失败555555...!你可能没有权限啊,快升级吧...</h2>-------------------------<a href="javascript:history.go(-1);">返回</a>');
exit ();
} else {
$json = '{"zt":0,"xx":"失败555555...!你可能没有权限啊,快升级吧..."}';
echo $json;
exit ();
}
}
}
}
有了代码,其实没什么好说的了,唠叨一句:
.根据group,action,fun获得key,这三个tp都有常量的,获得了key,根据key找到系统功能array的对应值,从里面提取出id,
然后判断这个id在不在角色表的funstr串当中就可以判定是否可以操作了。
还少了一块,吧系统功能array的每个key对应的值中的id存入角色表的funstr当中。这个就不献丑了。随后有时间附上源代码吧。
周末闲来无事。小文一篇,蜻蜓点水而已,只是说个思路。欢迎各路大神拍啊拍啊拍!!!