中的权限认证模块

出自

1.数据库结构

用户表

CREATE TABLE `think_user` (

`id` int(11) NOT NULL AUTO_INCREMENT, //主键id

`username` varchar(30) DEFAULT NULL, //用户名

`password` varchar(32) DEFAULT NULL, //密码

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

权限节点表

CREATE TABLE `think_auth_rule` (

`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, //主键id

`name` char(80) NOT NULL DEFAULT ” COMMENT ‘规则唯一标识’, //描述

`url` char(20) NOT NULL DEFAULT ” COMMENT ‘规则普通话名称’,
//路径如:Index/index

`status` tinyint(1) NOT NULL DEFAULT ‘1’ COMMENT
‘状态:为1正常,为0禁用’,

`pcontroller` char(80) NOT NULL, //上次控制器

`condition` char(100) NOT NULL DEFAULT ” COMMENT
‘规则表明式,为空表示存在就印证,不为空表示依照基准验’,

`type` tinyint(1) NOT NULL DEFAULT ‘1’,

PRIMARY KEY (`id`),

UNIQUE KEY `name` (`name`)

) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
COMMENT=’规则表’;

用户组–用户关联表

CREATE TABLE `think_auth_group_access` (

`uid` mediumint(8) unsigned NOT NULL COMMENT ‘用户id’,

`group_id` mediumint(8) unsigned NOT NULL COMMENT ‘用户组id’,

UNIQUE KEY `uid_group_id` (`uid`,`group_id`),

KEY `uid` (`uid`),

KEY `group_id` (`group_id`)

) ENGINE=MyISAM DEFAULT CHA陆风X8SET=utf8 COMMENT=’用户组明细表’;

用户组表

CREATE TABLE `think_auth_group` (

`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, //主键id

`name` char(100) NOT NULL DEFAULT ”,//用户组名称

`status` tinyint(1) NOT NULL DEFAULT ‘1’,//用户组状态

`rules` char(80) NOT NULL DEFAULT
”,//用户组关联的权能节点id(五个)

PRIMARY KEY (`id`)

) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHA奇骏SET=utf8
COMMENT=’用户组表’;

https://www.lyblog.net/detail/552.html

2.认证类

classAuth{

//默许配置

protected$_config= array(

‘AUTH_ON’=> true,//认证开关

‘AUTH_TYPE’=>1,//认证方式,1为实时认证;2为报到认证。

‘AUTH_GROUP’=>’think_auth_group’,//用户组数据表名

‘AUTH_GROUP_ACCESS’=>’think_auth_group_access’,//用户-用户组关系表

‘AUTH_RULE’=>’think_auth_rule’,//权限规则表

‘AUTH_USER’=>’think_user’//用户音信表

);

public function__construct() {

header(“Content-type: text/html; charset=utf-8”);

if(Config::get(‘auth_config’)) {

$this->_config=array_merge($this->_config,Config::get(‘auth_config’));//可设置配置项auth_config,此安插项为数组。

}

}

/**

*反省权限

* @param name
string|array须要证实的规则列表,援救逗号分隔的权限规则或索引数组

* @param uid  int认证用户的id

* @param string mode执行check的模式

* @param relation
string就算为’or’表示满意任一条规则即因而认证;如若为’and’则象征需满意全体条条框框才能经过认证

* @return boolean通过认证重返true;失利再次回到false

*/

public functioncheck($name,$uid,$type=1,$mode=’url’,$relation=’or’) {

if(!$this->_config[‘AUTH_ON’])

return true;

$authList=$this->getAuthList($uid,$type);//获取用户必要表明的拥有有效规则列表

if(is_string($name)) {

$name=strtolower($name);

$name=strpos($name,’,’)!== false ?explode(‘,’,$name): array($name);

}

$list= array();//保存验证通过的规则名

if($mode==’url’) {

$REQUEST=unserialize(strtolower(serialize($_REQUEST)) );

}

foreach($authListas$auth) {

$query=preg_replace(‘/^.+\?/U’,”,$auth);

if($mode==’url’&&$query!=$auth) {

parse_str($query,$param);//解析规则中的param

$intersect=array_intersect_assoc($REQUEST,$param);

$auth=preg_replace(‘/\?.*$/U’,”,$auth);

if(in_array($auth,$name)&&$intersect==$param)
{//借使节点相符且url参数知足

$list[]=$auth;

}

}else if(in_array($auth,$name)){

$list[]=$auth;

}

}

if($relation==’or’and !empty($list)) {

return true;

}

$diff=array_diff($name,$list);

if($relation==’and’and empty($diff)) {

return true;

}

return false;

}

/**

*基于用户id获取用户组,重回值为数组

* @param  uid int用户id

* @return array用户所属的用户组array(

*                                       
array(‘uid’=>’用户id’,’group_id’=>’用户组id’,’title’=>’用户组名称’,’rules’=>’用户组拥有的条条框框id,多个,号隔开’),

*                                        …)

*/

public functiongetGroups($uid) {

static$groups= array();

if(isset($groups[$uid]))

return$groups[$uid];

$user_groups=Db::view($this->_config[‘AUTH_GROUP_ACCESS’],’uid,group_id’)->view($this->_config[‘AUTH_GROUP’],’name,rules’,”{$this->_config[‘AUTH_GROUP_ACCESS’]}.group_id={$this->_config[‘AUTH_GROUP’]}.id”)

->where([‘uid’=>$uid,’status’=>1])->select();

$groups[$uid]=$user_groups?:array();

return$groups[$uid];

}

/**

*得到权限列表

* @param integer $uid用户id

* @param integer $type

*/

protected functiongetAuthList($uid,$type) {

static$_authList= array();//保存用户验证通过的权限列表

$t=implode(‘,’,(array)$type);

if(isset($_authList[$uid.$t])) {

return$_authList[$uid.$t];

}

if($this->_config[‘AUTH_TYPE’]==2&&
isset($_SESSION[‘_AUTH_LIST_’.$uid.$t])){

return$_SESSION[‘_AUTH_LIST_’.$uid.$t];

}

//读取用户所属用户组

$groups=$this->getGroups($uid);

$ids= array();//保存用户所属用户组设置的具有权限规则id

foreach($groupsas$g) {

$ids=array_merge($ids,explode(‘,’,trim($g[‘rules’],’,’)));

}

$ids=array_unique($ids);

if(empty($ids)) {

$_authList[$uid.$t]= array();

return array();

}

$map=array(

‘id’=>array(‘in’,$ids),

‘type’=>$type,

‘status’=>0,

);

//读取用户组全部权力规则

$rules=Db::table($this->_config[‘AUTH_RULE’])->where($map)->field(‘condition,name,url’)->select();

//循环规则,判断结果。

$authList= array();//

foreach($rulesas$rule) {

if(!empty($rule[‘condition’])) {//依据condition举行求证

$user=$this->getUserInfo($uid);//获取用户音讯,一维数组

$command=preg_replace(‘/\{(\w*?)\}/’,’$user[\’\\1\’]’,$rule[‘condition’]);

//dump($command);//debug

@(eval(‘$condition=(‘.$command.’);’));

if($condition) {

$authList[]=strtolower($rule[‘url’]);

}

}else{

//只要存在就记下

$authList[]=strtolower($rule[‘url’]);

}

}

$_authList[$uid.$t]=$authList;

if($this->_config[‘AUTH_TYPE’]==2){

//规则列表结果保存到session

$_SESSION[‘_AUTH_LIST_’.$uid.$t]=$authList;

}

returnarray_unique($authList);

}

/**

*得到用户资料,依据自个儿的情景读取数据库

*/

protected functiongetUserInfo($uid) {

static$userinfo=array();

if(!isset($userinfo[$uid])){

$userinfo[$uid]=Db::table($this->_config[‘AUTH_USER’])->where([‘id’=>$uid])->find();

}

return$userinfo[$uid];

}

}

 

3.登录时使用

public function login(){

$uid=1;  //登录后的用户id

vendor(“Auth”);
//因为是将认证类作为团结的第一方包写的,所以选择时索要开首入

$auth= newAuth();

$name=Request::instance()->controller().’/’.Request::instance()->action();
//如必要验证Index/index 登录的用户是或不是有操作该类的权位

$res=$auth->check($name,$uid);  //调用注脚措施里的证实

if(!$res){

echo’你没有权限’;

}else{

echo’登录成功’;

}

}

RBAC是哪些,能缓解哪些难点?

RBAC是Role-Based Access
Control的首字母,译成汉语即基于角色的权杖访问控制,说白了相当于用户通过角色与权力举办关联[其架构灵感源于操作系统的GBAC(GROUP-Based
Access
Control)的权限管理控制]。简单的来说,三个用户可以具有多少脚色,每2个角色有所多少权力。那样,就布局成“用户-剧中人物-权限”的授权模型。在这种模型中,用户与角色里面,剧中人物与权力以内,一般者是多对多的关系。其对应涉及如下:

图片 1

在很多的实际上运用中,系统不不过内需用户已毕不难的挂号,还亟需对分裂级其余用户对差距能源的拜会具有不相同的操作权限。且在商户费用中,权限管理系列也成了重复支付功用最高的二个模块之一。而在多套系统中,对应的权杖管理只可以满意自个儿系统的管住必要,无论是在数据库设计、权限访问和权限管理机制格局上都只怕不一致,那种不致性也就存在如下的憋端:

  • 维护多套系统,重复造轮子,时间没用在刀刃上
  • 用户管理、社团机制等数码再次维护,数据的完整性、一致性很难取得保险
  • 权力系统规划不一样,概念通晓不一致,及相应技术差距,系统之间集成存在难点,单点登录难度大,也复杂的商家系统带来不方便

RBAC是根据不断推行之后,指出的1个相比成熟的访问控制方案。实践注脚,选取基于RBAC模型的权力管理体系具有以下优势:由于角色、权限以内的生成比角色、用户关系里面的变型相对要慢得多,减小了授权管理的复杂性,降低管理支出;而且可以灵活地襄助使用种类的安全策略,并对运用序列的更动有很大的紧缩性;在操作上,权限分配直观、简单了然,便于使用;分级权限适合分层的用户级格局;重用性强。

ThinkPHP中RBAC已毕系统

ThinkPHP中RBAC基于Java的Spring的Acegi安全部系作为参考原型,并做了相应的简化处理,以适应当前的ThinkPHP结构,提供贰个多层、可定制的平安系统来为利用开发提供安全控制。安全部系中根本有以下几某些:

  • 平安拦截器
  • 证实管理器
  • 核定访问管理器
  • 运维地点管理器

平安拦截器

康宁拦截器就好比一道道门,在系统的安全防护系统中可能存在诸多例外的安全控制环节,一旦某些环节你未通过安全系统认证,那么安全拦截器就会实施拦截。

表达管理器

 

严防种类的率先道门就是表明管理器,认证管理器负责控制你是什么人,一般它通过验证你的焦点(寻常是一个用户名)和您的凭证(经常是1个密码),大概更加多的资料来落成。更简便的说,认证管理器验证你的地位是或不是在鹤壁防护序列授权范围以内。

做客决策管理

 

尽管通过了求证管理器的身份验证,不过并不意味着你可以在系统里头肆意妄为,因为您还亟需通过访问决策管理这道门。访问决策管理器对用户进行授权,通过考虑你的身价验证新闻和与受保险能源事关的安全品质决定是是或不是足以进来系统的某些模块,和开展某项操作。例如,安全规则规定唯有COO才同意访问某个模块,而你并不曾被予以首席执行官权限,那么安全拦截器会阻止你的造访操作。
核定访问管理器不能独立运营,必须首先依赖认证管理器举行身份确认,因而,在加载访问决策过滤器的时候已经包罗了验证管理器和表决访问管理器。 
为了满意使用的差距须求,ThinkPHP
在进展访问决策管理的时候利用两种格局:登录方式和当下格局。登录格局,系统在用户登录的时候读取改用户所独具的授权音讯到
Session,下次不再重复拿到授权音信。相当于说就算管理员对该用户展开了权力修改,用户也非得在下次报到后才能奏效。即时方式就是为着缓解地点的题材,在历次访问系统的模块或许操作时候,举办即便验证该用户是或不是持有该模块和操作的授权,从更高水准上保证了系统的安全。

运作地点管理器

 

运行地点管理器的用处在大部用到连串中是个其余,例如有些操作和模块需要三个地点的酒泉需要,运营地点管理器可以用另3个地位替换你日前的地方,从而允许你拜访应用连串之中更深处的受保证对象。这一层安全部系近来的
RBAC 中一向不完结。

ThinkPHP中RBAC认证流程

对应上边的平安系统,ThinkPHP 的 RBAC 认证的经过大概如下:

  1. 判定当前模块的当前操作是不是要求表达
  2. 假诺急需表明并且没有登录,跳到表达网关,借使已经登录 执行5
  3. 经过信托讲明举办用户地方声明
  4. 收获用户的裁定访问列表
  5. 判定当前用户是不是有所访问权限

权限管理的具体落实进度

RBAC相关的数据库介绍

在ThinkPHP完整包,包含了RBAC处理类RBAC.class.php文件,位于Extend/Library/ORG/Util。打开该公文,其中就富含了运用RBAC必备的4张表,SQL语句如下(复制后请替换表前缀):

复制

  1. CREATE TABLE IF NOT EXISTS `ly_access` (
  2. `role_id`
    smallint(6) unsigned NOT NULL,
  3. `node_id`
    smallint(6) unsigned NOT NULL,
  4. `level`
    tinyint(1) NOT NULL,
  5. `module`
    varchar(50) DEFAULT NULL,
  6. KEY `groupId` (`role_id`),
  7. KEY `nodeId` (`node_id`)
  8. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  9.  
  10. CREATE TABLE IF NOT EXISTS `ly_node` (
  11. `id`
    smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  12. `name`
    varchar(20) NOT NULL,
  13. `title`
    varchar(50) DEFAULT NULL,
  14. `status`
    tinyint(1) DEFAULT ‘0’,
  15. `remark`
    varchar(255) DEFAULT NULL,
  16. `sort`
    smallint(6) unsigned DEFAULT NULL,
  17. `pid`
    smallint(6) unsigned NOT NULL,
  18. `level`
    tinyint(1) unsigned NOT NULL,
  19. PRIMARY KEY (`id`),
  20. KEY `level`
    (`level`),
  21. KEY `pid`
    (`pid`),
  22. KEY `status` (`status`),
  23. KEY `name`
    (`name`)
  24. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  25.  
  26. CREATE TABLE IF NOT EXISTS `ly_role` (
  27. `id`
    smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  28. `name`
    varchar(20) NOT NULL,
  29. `pid`
    smallint(6) DEFAULT NULL,
  30. `status`
    tinyint(1) unsigned DEFAULT NULL,
  31. `remark`
    varchar(255) DEFAULT NULL,
  32. PRIMARY KEY (`id`),
  33. KEY `pid`
    (`pid`),
  34. KEY `status` (`status`)
  35. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
  36.  
  37. CREATE TABLE IF NOT EXISTS `ly_role_user` (
  38. `role_id`
    mediumint(9) unsigned DEFAULT NULL,
  39. `user_id`
    char(32) DEFAULT NULL,
  40. KEY `group_id` (`role_id`),
  41. KEY `user_id` (`user_id`)
  42. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;

上边对RBAC相关的多少库表及字段作一下介绍:

表名

字段名

字段类型

作用

ly_user

id

INT

用户ID(唯一识别号)

username

VARCHAR(16)

用户名

password

VARCHAR(32)

密码

email

VARCHAR(100)

用户邮箱

create_time

TIMESTAMP

开创时间(时间戳)

logintime

TIMESTAMP

不久前五次登录时间(时间戳)

loginip

VARCHAR(15)

近期报到的IP地址

status

TINYINT(1)

启用处境:0:表示禁用;1:表示启用

remark

VARCHAR(255)

备注新闻

ly_role

id

INT

角色ID

name

VARCHAR(20)

角色名称

pid

SMALLINT(6)

父剧中人物对应ID

status

TINYINT(1)

启用情形(同上)

remark

VARCHAR(255)

备考音讯

ly_node

id

SMALLINT(6)

节点ID

name

VARCHAR(20)

节点名称(英文名,对应使用控制器、应用、方法名)

title

VARCHAR(50)

节点汉语名(方便看懂)

status

TINYINT(1)

启用情形(同上)

remark

VARCHAR(255)

备考新闻

sort

SMALLINT(6)

排序值(暗中同意值为50)

pid

SMALLINT(6)

父节点ID(如:方法pid对应相应的控制器)

level

TINYINT(1)

节点类型:1:表示应用(模块);2:表示控制器;3:表示方法

ly_role_user

user_id

INT

用户ID

role_id

SMALLINT(6)

角色ID

ly_access

role_id

SMALLINT(6)

角色ID

node_id

SMALLINT(6)

节点ID

level

 

 

module

 

 

以下是数据库表各字段的涉嫌关系:

图片 2

完成RBAC管理的前导性工作

根据ThinkPHP完成RBAC的权柄管理连串中,首先要做一些前导性的行事(系统数据库设计TP已经为大家已毕了),首要分以下多少个方面:

  • 用户(增、删、改、查)
  • 角色(增、删、改、查)
  • 节点(增、删、改、查)
  • 陈设权力(更新权限)

切实落成的代码如下(相关解释均在诠释之中):

复制

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: LiuYang
  5. * Date: 14-9-6
  6. * Time: 下午9:54
  7. * Description:
    基于ThinkPHP已毕的权柄管理系列
  8. */
  9.  
  10. class RbacAction extends CommonAction {
  11.  
  12. //初阶化操作
  13. function
    _initialize(){
  14. if(!IS_AJAX) $this->error(‘你拜访的页面不存在,请稍后再试’);
  15. }
  16.  
  17.  
  18. //用户列表
  19. public function index(){
  20. $db = M(‘user’);
  21.  
  22. //当前页码
  23. $pageNum =
    I(‘post.pageNum’,1,’int’);
  24. //每页显示条数
  25. $numPerPage =
    I(‘post.numPerPage’,C(“numPerPage”),’int’);
  26. //总页码数
  27. $totalCount =
    $db->count();
  28.  
  29. $this->totalCount =
    $totalCount;
  30. $this->numPerPage =
    $numPerPage;
  31. $this->items = D(‘UserRelation’)->relation(true)->page($pageNum, $numPerPage)->select();
  32. $this->display();
  33. }
  34.  
  35. //添加编制用户弹层表单
  36. public function addUser(){
  37. //假设设置了uid,则为编写用户,否则为扩张用户
  38. $this->role = M(‘role’)->where(‘status =
    1’)->field(‘id,name’)->select();
  39.  
  40. if(isset($_GET[‘uid’])) {
  41. $this->userinfo = M(‘user’)->where( “id = $_GET[uid]” )->find();
  42. }
  43. $this->display();
  44. }
  45.  
  46. //添加及编辑用户表单处理
  47. public function addUserHandler(){
  48.  
  49. $db = M(‘user’);
  50. if($_POST[‘id’]) {
  51. //如若存在ID,即意味着更新
  52. $data =
    array(
  53. ‘id’ => I(‘post.id’,”,’int’),
  54. ‘username’
    => I(‘username’, ”, ‘string’),
  55. ‘status’
    => I(‘status’,”, ‘int’),
  56. ‘remark’
    => I(‘remark’),
  57. ‘logintime’
    => time(),
  58. ‘loginip’
    => get_client_ip()
  59. );
  60.  
  61. if($_POST[‘password’])
    $data[‘password’] = I(‘password’,”, ‘md5’);
  62. if($db->save($data)) {
  63. $roleuser =
    M(‘role_user’);
  64.  
  65. $roleuser->where(“id =
    $data[id]”)->delete();
  66.  
  67. $roleuser->add(array(
  68. ‘role_id’
    => I(‘role’,”,’intval’),
  69. ‘user_id’
    => $data[id]
  70. ));
  71.  
  72. $this->ajaxReturn(array(
  73. ‘statusCode’
    => 200,
  74. ‘message’
    => ‘更新成功’
  75. ));
  76. } else {
  77. $this->ajaxReturn(array(
  78. ‘statusCode’
    => 300,
  79. ‘message’
    => ‘操作战败’
  80. ));
  81. }
  82.  
  83. return ;
  84. }
  85.  
  86. //添加表单处理
  87. $data =
    array(
  88. ‘username’
    => I(‘username’, ”, ‘string’),
  89. ‘password’
    => I(‘password’, ”, ‘md5’),
  90. ‘status’
    => I(‘status’,”, ‘int’),
  91. ‘remark’
    => I(‘remark’),
  92. ‘logintime’
    => time(),
  93. ‘loginip’
    => get_client_ip()
  94. );
  95. if($uid = M(‘user’)->add($data)) {
  96. $roleuser =
    M(‘role_user’);
  97.  
  98. $roleuser->where(“id =
    $uid”)->delete();
  99.  
  100. $roleuser->add(array(
  101. ‘role_id’
    => I(‘role’,”,’intval’),
  102. ‘user_id’
    =>
    $uid
  103. ));
  104.  
  105. $this->ajaxReturn(array(
  106. ‘statusCode’
    => 200,
  107. ‘message’
    => ‘操作成功’,
  108. ‘navTabId’
    => ”,
  109. ‘rel’ => ”,
  110. ‘callbackType’ => ”,
  111. ‘forwardUrl’
    => ”,
  112. ‘confirmMsg’
    => ”
  113. ));
  114. } else {
  115. $this->ajaxReturn(array(
  116. ‘statusCode’
    => 300,
  117. ‘message’
    => ‘操作失利’
  118. ));
  119. }
  120. }
  121.  
  122. //启用或楚用用户
  123. public function resume(){
  124. $id = I(‘get.id’,’0′,’int’);
  125. $db = M(‘user’);
  126. $status =
    $db->where(“id = $id”)->getField(‘status’);
  127. $status =
    ($status == 1)? 0 : 1 ;
  128. if($db->where(“id = $id”)->setField(‘status’,
    $status)){
  129. $this->ajaxReturn(array(
  130. ‘statusCode’
    => 1,
  131. ‘message’
    => ‘操作成功’,
  132. ‘navTabId’
    =>$_GET[‘navTabId’]
  133. ));
  134. } else {
  135. $this->ajaxReturn(array(
  136. ‘statusCode’
    => 0,
  137. ‘message’
    => ‘操作失利’
  138. ));
  139. }
  140. }
  141.  
  142. //删除用户
  143. public function deleteUserHandler(){
  144. $id = I(‘get.uid’,0,’int’);
  145. if( M(‘user’)->delete($id) ) {
  146. $this->ajaxReturn(array(
  147. ‘statusCode’
    => 1,
  148. ‘message’
    => ‘删除成功’,
  149. ‘navTabId’
    => $_GET[‘navTabId’]
  150. ));
  151. } else {
  152. $this->ajaxReturn(array(
  153. ‘statusCode’
    => 0,
  154. ‘message’
    => ‘删除成功’,
  155. ‘navTabId’
    => $_GET[‘navTabId’]
  156. ));
  157. }
  158. }
  159.  
  160. //节点列表
  161. public function node(){
  162. $node =
    M(‘node’)->where(array(‘status’=>1))->order(‘sort’)->select();
  163. $this->node =
    node_merge($node);
  164. $this->display();
  165. }
  166.  
  167. //添加及编辑节点弹层表单
  168. public function addNode(){
  169. //添加表单暗中同意意况
  170. $this->info = array(
  171. ‘level’
    => I(‘get.level’,1,’int’),
  172. ‘pid’ => I(‘get.pid’,0,’int’),
  173. ‘status’
    => 1,
  174. ‘sort’ => 50
  175. );
  176. switch ($this->info[‘level’]){
  177. case 1: {
  178. $this->label = “应用”;
  179. break;
  180. }
  181. case 2: {
  182. $this->label = “控制器”;
  183. break;
  184. }
  185. case 3: {
  186. $this->label = “方法”;
  187. break;
  188. }
  189. }
  190. if($_GET[‘id’]) {
  191. //编辑情势
  192. $this->info = M(‘node’)->where(array(‘id’=>$_GET[‘id’]))->find();
  193. }
  194. $this->display();
  195. }
  196.  
  197. //添加及编辑节点表单处理
  198. public function addNodeHandler(){
  199. $id =
    $_POST[‘id’];
  200. $db = M(‘node’);
  201. if($id) {
  202. //更新
  203. if($db->save($_POST)) {
  204. $this->ajaxReturn(array(
  205. ‘statusCode’
    => 200,
  206. ‘message’
    => ‘添加事业有成’,
  207. ‘navTabId’
    => $_GET[‘navTabId’]
  208. ));
  209. } else {
  210. $this->ajaxReturn(array(
  211. ‘statusCode’
    => 300,
  212. ‘message’
    => ‘更新战败’,
  213. ‘navTabId’
    => $_GET[‘navTabId’]
  214. ));
  215. }
  216. }else {
  217. //保存
  218. if($db->add($_POST)) {
  219. $this->ajaxReturn(array(
  220. ‘statusCode’
    => 200,
  221. ‘message’
    => ‘添加事业有成’,
  222. ‘navTabId’
    => $_GET[‘navTabId’]
  223. ));
  224. } else {
  225. $this->ajaxReturn(array(
  226. ‘statusCode’
    => 300,
  227. ‘message’
    => ‘添加失利’,
  228. ‘navTabId’
    => $_GET[‘navTabId’]
  229. ));
  230. }
  231. }
  232. }
  233.  
  234. //删除节点
  235. public function deleteNodeHandler(){
  236. $id = I(‘get.id’,’0′,’int’);
  237. $db = M(‘node’);
  238. $data =
    $db->where(array(‘pid’=>$id))->field(‘id’)->find();
  239. if($data) {
  240. $this->ajaxReturn(array(
  241. ‘statusCode’
    => 0,
  242. ‘message’
    => ‘你请求删除的节点存在子节点,不可直接删除’
  243. ));
  244. } else {
  245. if($db->delete($id)) {
  246. $this->ajaxReturn(array(
  247. ‘statusCode’=> 1,
  248. ‘message’
    => ‘删除成功’
  249. ));
  250. } else {
  251. $this->ajaxReturn(array(
  252. ‘statusCode’
    => 0,
  253. ‘message’
    => ‘删除失败’
  254. ));
  255. }
  256. }
  257. //if($data[‘level’]
    === 3)
  258. }
  259.  
  260. //角色管理
  261. public function role(){
  262. $this->role = M(‘role’)->select();
  263. $this->display();
  264. }
  265.  
  266. //添加及编辑剧中人物
  267. public function addRole(){
  268. if($_GET[‘rid’]) {
  269. $id = I(‘get.rid’,0,’int’);
  270. $this->role = M(‘role’)->find($id);
  271. }
  272. $this->display();
  273. }
  274.  
  275. //添加角色表单处理
  276. public function addRoleHandler(){
  277. $db = M(‘role’);
  278. if($_POST[‘id’]) {
  279. //更新
  280. if($db->save($_POST)) {
  281. $this->ajaxReturn(array(
  282. ‘statusCode’=> 200,
  283. ‘message’
    => “剧中人物音讯更新成功”
  284. ));
  285. } else {
  286. $this->ajaxReturn(array(
  287. ‘statusCode’
    => “300”,
  288. ‘message’
    => ‘剧中人物音信更新失败’
  289. ));
  290. }
  291. } else {
  292. //添加表单处理
  293. if($db ->add($_POST)){
  294. $this->ajaxReturn(array(
  295. ‘statusCode’=> 200,
  296. ‘message’
    => “角色添加成功”
  297. ));
  298. }else {
  299. $this->ajaxReturn(array(
  300. ‘statusCode’
    => 300,
  301. ‘message’
    => ‘剧中人物添加失利’
  302. ));
  303. }
  304. }
  305. }
  306.  
  307. //删除角色
  308. public function deleteRole(){
  309.  
  310. }
  311.  
  312. //快束启用或楚用用户
  313. public function resumeRole(){
  314. $id = I(‘get.rid’,0, ‘int’);
  315. $db = M(‘role’);
  316. $status =
    $db->where(“id = $id”)->getField(‘status’);
  317. $status =
    ($status == 1)? 0 : 1 ;
  318. if($db->where(“id = $id”)->setField(‘status’,
    $status)){
  319. $this->ajaxReturn(array(
  320. ‘statusCode’
    => 1,
  321. ‘message’
    => ‘操作成功’,
  322. ‘navTabId’
    =>$_GET[‘navTabId’]
  323. ));
  324. } else {
  325. $this->ajaxReturn(array(
  326. ‘statusCode’
    => 0,
  327. ‘message’
    => ‘操作失败’
  328. ));
  329. }
  330. }
  331.  
  332.  
  333. //给用户增加节点权限
  334. public function access(){
  335. $rid =
    I(‘rid’,0 ,’intval’);
  336. $node =
    M(‘node’)->where(array(‘status’=>1))->field(array(‘id’,’title’,’pid’,’name’,’level’))->order(‘sort’)->select();
  337.  
  338. //获取原有权限
  339. $access =
    M(‘access’)->where(“role_id = $rid”)->getField(‘node_id’,true);
  340. $this->node =
    node_merge($node,$access);
  341. $this->assign(‘rid’,$rid)->display();
  342. }
  343.  
  344. //添加节点权限表单处理
  345. public function accessHandler(){
  346. $rid =
    I(‘rid’, ”, ‘intval’);
  347. $db = M(‘access’);
  348. //清空原有权限
  349. $db->where(“role_id =
    $rid”)->delete();
  350.  
  351. //插入新的权能
  352. $data =
    array();
  353.  
  354. foreach
    ($_POST[‘access’] as $v) {
  355. $tmp =
    explode(‘_’, $v);
  356. $data[]
    = array(
  357. ‘role_id’=> $rid,
  358. ‘node_id’=> $tmp[0],
  359. ‘level’=>$tmp[1]
  360. );
  361. }
  362. if($db->addAll($data)) {
  363. $this->ajaxReturn(array(
  364. ‘statusCode’=> 200,
  365. ‘message’
    => ‘权限更新成功’
  366. ));
  367. } else {
  368. $this->ajaxReturn(array(
  369. ‘statusCode’
    => 300,
  370. ‘message’
    => ‘权限更新败北’
  371. ));
  372. }
  373.  
  374. }
  375. }

ThinkPHP中RBAC类的详解

在ThinkPHP处理权限管理中,真正的难关并不是在RBAC类的运用上,上面相关的处理(权限配置,节点管理等);所以当成功上述工作,其实RBAC系统已经形成了九成。上边先从ThinkPHP中RBAC的安插说起(详细请参考对应的注解内容):

复制

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: LiuYang
  5. * Date: 14-9-29
  6. * Time: 下午9:36
  7. * Description:
    ThinkPHP中RBAC处理类的配置文件
  8. */
  9.  
  10. return array(
  11.  
  12. “USER_AUTH_ON” => true, //是还是不是打开权限验证(必配)
  13. “USER_AUTH_TYPE” => 1, //验证情势(壹 、登录验证;② 、实时验证)
  14.  
  15. “USER_AUTH_KEY” => ‘uid’, //用户认证识别号(必配)
  16. “ADMIN_AUTH_KEY” => ‘superadmin’, //一级管理员识别号(必配)
  17. “USER_AUTH_MODEL” => ‘user’, //验证用户表模型
    ly_user
  18. ‘USER_AUTH_GATEWAY’ => ‘/Public/login’,
    //用户认证退步,跳转U汉兰达L
  19.  
  20. ‘AUTH_PWD_ENCODEEvoque’=>’md5’, //默许密码加密方法
  21.  
  22. “RBAC_SUPERADMIN” => ‘admin’, //超级管理员名称
  23.  
  24.  
  25. “NOT_AUTH_MODULE” => ‘Index,Public’,
    //无需认证的控制器
  26. “NOT_AUTH_ACTION” => ‘index’, //无需认证的点子
  27.  
  28. ‘REQUIRE_AUTH_MODULE’ => ”, //默认必要证实的模块
  29. ‘REQUIRE_AUTH_ACTION’ => ”, //默许要求表明的动作
  30.  
  31. ‘GUEST_AUTH_ON’ => false, //是或不是打开游客授权访问
  32. ‘GUEST_AUTH_ID’ => 0, //游客标记
  33.  
  34. “RBAC_ROLE_TABLE” => ‘ly_role’, //角色表名称(必配)
  35. “RBAC_USER_TABLE” => ‘ly_role_user’,
    //用户剧中人物中间表名称(必配)
  36. “RBAC_ACCESS_TABLE” => ‘ly_access’, //权限表名称(必配)
  37. “RBAC_NODE_TABLE” => ‘ly_node’, //节点表名称(必配)
  38. );

注意:

  • 以上部分配置项并非必须的,但标有“必配”,则必须配备
  • 无需表达的权杖和形式与需求注明的模块和动作可以依照必要拔取性配置,还有一些权力相关陈设并未列表出

RBAC处理类提供静态的方法

ThinkPHP的RBAC处理类提须求我们许多相关的静态方法如下:

方法名 接收参数说明 返回值 说明
RBAC::authenticate($map,$model=”);
  • $map:ThinkPHP数据库处理类的where条件参数
  • $model:用户表名,默认取配置文件C('USER_AUTH_MODEL')
array

RBAC::authenticate(array("username"=>"admin","userpwd" => I('POST.pwd','', 'md5')));

返回值是在用户表中,以$map为条件where的查阅结果集

0RBAC::saveAccessList($authId=null);
  • $authId:用户识别号,默认取C('USER_AUTH_KEY');
返回一个空值 如果验证方式为登录验证,则将权限写入session中,否则不作任何处理
RBAC::getRecordAccessList($authId=null,$module=”);
  • $authId:用户识别号(可不传)
  • $module:当前操作的模块名称
Array 返回一个包含权限的ID的数组
RBAC::checkAccess() 返回true或false 检查当前操作是否需要认证(根据配置中需要认证和不需要评论的模块或方法得出)
RBAC::checkLogin() true 如果当前操作需要认证且用户没有登录,继续检测是否开启游客授权。如果开启游客授权,则写入游客权限;否则跳到登录页
RBAC::AccessDecision($appName=APP_NAME)
  • $appName:选传,有默认值
  • true:表示有操作权限
  • false:无操作权限
AccessDecision($appName=APP_NAME)方法,检测当前项目模块操作,是否存在于$_SESSION[‘_ACCESS_LIST’]数组中$_SESSION[‘_ACCESS_LIST’][‘当前操作’][‘当前模块’][‘当前操作’]是否存在。如果存在表示有权限,返回true;否则返回flase。
RBAC::getAccessList($authId)
  • $authId:用户识别号(选传,程序自动获取)
Array 通过数据库查询取得当前认证号的所有权限列表
RBAC::getModuleAccessList($authId,$module)
  • $authId:用户识别号(必)
  • $module:对应的模块(必)
Array 返回指定用户可访问的节点权限数组

注意:在使用RBAC::AccessDecision()艺术时,假若您开启了档次分组,则必须传入当前分组,代码如下:

复制

  1. //权限验证
  2. if(C(‘USER_AUTH_ON’) && !$notAuth) {
  3. import(‘ORG.Util.RBAC’);
  4. //使用了花色分组,则必须引入GROUP_NAME
  5. RBAC::AccessDecision(GROUP_NAME) || $this->error(“你未曾对应的权能”);
  6. }

RBAC处理类的骨子里运用

在形成用户登录,角色创立,节点增删改查的行事后,就只剩余了RBAC如何在对应程序代码中运用了。挻简单的,只用在本来的代码其余上改动多少个地点即可。

  • 用户登录时,写入用户权限
  • 用户操作时,举行权力验证

上面是用户登录时的兑现代码:

复制

  1. >?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: LiuYang
  5. * Date: 14-8-24
  6. * Time: 下午5:23
  7. * Description: 用户登户及退出控制器
  8. */
  9.  
  10. class LoginAction extends Action {
  11.  
  12. //用户登录视图
  13. public function index(){
  14. //…
  15. }
  16.  
  17. //用户登录处理表单
  18. public function loginHandle(){
  19. if(!IS_POST) halt(‘页面不设有,请稍后再试’);
  20. if(session(‘verify’) != I(‘param.verify’,”,’md5′)) {
  21. $this->error(‘验证码错误’, U(‘Admin/Login/index’));
  22. }
  23.  
  24. $user =
    I(‘username’,”,’string’);
  25. $passwd =
    I(‘password’,”,’md5′);
  26.  
  27. $db = M(‘user’);
  28. $userinfo =
    $db->where(“username = ‘$user’ AND password =
    ‘$passwd'”)->find();
  29.  
  30. if(!$userinfo)
    $this->error(‘用户名或密码错误’, U(‘Admin/Login/index’));
  31.  
  32. if(!$userinfo[‘status’])
    $this->error(‘该用户被锁定,一时不可登录’, U(‘Admin/Login/index’));
  33.  
  34. //更新登录音讯
  35. $db->save(array(“id”=> $userinfo[“id”], “logintime”=>
    time(), “loginip” => get_client_ip()));
  36.  
  37. //写入session值
  38. session(C(“USER_AUTH_KEY”),
    $userinfo[“id”]);
  39. session(“username”,
    $userinfo[“username”]);
  40. session(“logintime”,
    $userinfo[“logintime”]);
  41. session(“loginip”,$user[“loginip”]);
  42.  
  43. //若是为一流管理员,则无需验证
  44. if($userinfo[‘username’] == C(‘RBAC_SUPERADMIN’))
    {
  45. session(C(‘ADMIN_AUTH_KEY’),
    true);
  46. }
  47.  
  48. //载入RBAC类
  49. import(‘ORG.Util.RBAC’);
  50. //读取用户权限
  51. RBAC::saveAccessList();
  52.  
  53. $this->success(‘登录成功’, U(‘Admin/Index/index’));
  54. }
  55.  
  56. //登出登录
  57. public function logOut(){
  58. //…
  59. }
  60.  
  61. //验证码
  62. public function verify(){
  63. //…
  64. }
  65. }

继之在控制器目录创设一个CommonAction.class.php文本,然后改写全体要权限验证的类,让其后续自CommonAction。代码如下:

复制

  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: LiuYang
  5. * Date: 14-9-3
  6. * Time: 下午8:40
  7. * Description: 操作权限验证
  8. */
  9.  
  10. class CommonAction extends Action {
  11. function
    _initialize(){
  12. if(!isset($_SESSION[C(‘USER_AUTH_KEY’)])) {
  13. $this->redirect(‘Admin/Login/index’);
  14. }
  15.  
  16. $notAuth =
    in_array(MODULE_NAME, explode(‘,’, C(‘NOT_AUTH_MODULE’))) || in_array(ACTION_NAME, C(‘NOT_AUTH_ACTION’));
  17.  
  18. //权限验证
  19. if(C(‘USER_AUTH_ON’)
    && !$notAuth) {
  20. import(‘ORG.Util.RBAC’);
  21. //使用了档次分组,则必须引入GROUP_NAME
  22. RBAC::AccessDecision(GROUP_NAME) || $this->error(“你没有相应的权位”);
  23. }
  24. }
  25. }

ThinkPHP中提供了二个_initialize()办法,是在类初阶化就会履行的,也等于一旦前边控制器继承自CommonAction类,就会在作相应操作时,执行_initialize()方法。

正文以上实例代码及有关源码下载:

下载EER图 下载源码

人无完人,肯定有不足之处,望拍砖率领(本文完)。