RBAC是Role-Based Access Control的首字母,译成中文即基于角色的权限接见掌握,说白了也就是用户经由历程角色与权限举行关联[其架构灵感来源于操纵系统的GBAC(GROUP-Based Access Control)的权限治理掌握]。简朴的来讲,一个用户可以具有多少角色,每个角色具有多少权限。如许,就构形成“用户-角色-权限”的受权模子。在这类模子中,用户与角色之间,角色与权限之间,平常者是多对多的关联。其对应关联以下:
在许多的现实运用中,系统不只是需要用户完成简朴的注册,还需要对差别级别的用户对差别资本的接见具有差别的操纵权限。且在企业开辟中,权限治理系统也成了反复开辟效力最高的一个模块之一。而在多套系统中,对应的权限治理只能满足本身系统的治理需要,无论是在数据库设想、权限接见和权限治理机制体式格局上都能够差别,这类不致性也就存在以下的憋端:
• 庇护多套系统,反复造轮子,时刻没用在刀刃上
• 用户治理、构造机制等数据反复庇护,数据的完整性、一致性很难获得保证
• 权限系统设想差别,观点明白差别,及响应手艺差别,系统之间集成存在题目,单点登录难度大,也庞杂的企业系统带来难题
RBAC是基于不停实践以后,提出的一个比较成熟的接见掌握计划。实践表明,采纳基于RBAC模子的权限治理系统具有以下上风:由于角色、权限之间的变化比角色、用户关联之间的变化相对要慢许多,减小了受权治理的庞杂性,下降治理开支;而且可以天真地支撑运用系统的平安策略,并对运用系统的变化有很大的伸缩性;在操纵上,权限分派直观、轻易明白,便于运用;分级权限合适分层的用户级情势;重用性强。
ThinkPHP中RBAC完成系统
ThinkPHP中RBAC基于Java的Spring的Acegi平安系统作为参考原型,并做了响应的简化处置惩罚,以顺应当前的ThinkPHP构造,供应一个多层、可定制的平安系统来为运用开辟供应平安掌握。平安系统中重要有以下几部份:
• 平安阻拦器
• 认证治理器
• 决议计划接见治理器
• 运转身份治理器
平安阻拦器
平安阻拦器就比如一道道门,在系统的平安防护系统中能够存在许多差别的平安掌握环节,一旦某个环节你未经由历程平安系统认证,那末平安阻拦器就会实行阻拦。
认证治理器
防护系统的第一道门就是认证治理器,认证治理器担任决议你是谁,平常它经由历程考证你的主体(通常是一个用户名)和你的凭据(通常是一个暗码),或许更多的材料来做到。更简朴的说,认证治理器考证你的身份是不是在平安防护系统受权局限以内。
接见决议计划治理
虽然经由历程了认证治理器的身份考证,然则并不代表你可以在系统内里肆意妄为,由于你还需要经由历程接见决议计划治理这道门。接见决议计划治理器对用户举行受权,经由历程斟酌你的身份认证信息和与受庇护资本关联的平安属性决议是是不是可以进入系统的某个模块,和举行某项操纵。比方,平安划定规矩划定只需主管才许可接见某个模块,而你并没有被授与主管权限,那末平安阻拦器会阻拦你的接见操纵。
决议计划接见治理器不能零丁运转,必需起首依靠认证治理器举行身份确认,因而,在加载接见决议计划过滤器的时刻已包括了认证治理器和决议计划接见治理器。
为了满足运用的差别需要,ThinkPHP 在举行接见决议计划治理的时刻采纳两种形式:登录形式和立即形式。登录形式,系统在用户登录的时刻读取改用户所具有的受权信息到 Session,下次不再从新猎取受权信息。也就是说纵然治理员对该用户举行了权限修正,用户也必需在下次登录后才见效。立即形式就是为了处置惩罚上面的题目,在每次接见系统的模块或许操纵时刻,举行纵然考证该用户是不是具有该模块和操纵的受权,从更高程度上保证了系统的平安。
运转身份治理器
运转身份治理器的用处在大多数运用系统中是有限的,比方某个操纵和模块需要多个身份的平安需求,运转身份治理器可以用另一个身份替代你现在的身份,从而许可你接见运用系统内部更深处的受庇护对象。这一层平安系统现在的 RBAC 中还没有完成。
ThinkPHP中RBAC认证流程
对应上面的平安系统,ThinkPHP 的 RBAC 认证的历程大抵以下:
1、推断当前模块的当前操纵是不是需要认证
2、假如需要认证而且还没有登录,跳到认证网关,假如已登录 实行5
3、经由历程托付认证举行用户身份认证
4、猎取用户的决议计划接见列表
5、推断当前用户是不是具有接见权限
权限治理的细致完成历程
RBAC相干的数据库引见
在ThinkPHP完整包,包括了RBAC处置惩罚类RBAC.class.php文件,
位于Extend/Library/ORG/Util
。翻开该文件,其中就包括了运用RBAC必备的4张表,SQL语句以下(复制后请替代表前缀):
CREATE TABLE IF NOT EXISTS `think_access` ( `role_id` smallint(6) unsigned NOT NULL, `node_id` smallint(6) unsigned NOT NULL, `level` tinyint(1) NOT NULL, `module` varchar(50) DEFAULT NULL, KEY `groupId` (`role_id`), KEY `nodeId` (`node_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;CREATE TABLE IF NOT EXISTS `think_node` ( `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `title` varchar(50) DEFAULT NULL, `status` tinyint(1) DEFAULT '0', `remark` varchar(255) DEFAULT NULL, `sort` smallint(6) unsigned DEFAULT NULL, `pid` smallint(6) unsigned NOT NULL, `level` tinyint(1) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `level` (`level`), KEY `pid` (`pid`), KEY `status` (`status`), KEY `name` (`name`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;CREATE TABLE IF NOT EXISTS `think_role` ( `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `pid` smallint(6) DEFAULT NULL, `status` tinyint(1) unsigned DEFAULT NULL, `remark` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `pid` (`pid`), KEY `status` (`status`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;CREATE TABLE IF NOT EXISTS `think_role_user` ( `role_id` mediumint(9) unsigned DEFAULT NULL, `user_id` char(32) DEFAULT NULL, KEY `group_id` (`role_id`), KEY `user_id` (`user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
下面临RBAC相干的数据库表及字段作一下引见:
表名 | 字段名 | 字段范例 | 作用 |
---|---|---|---|
ly_user | id | INT | 用户ID(唯一识别名) |
username | VARCHAR(16) | 用户名 | |
password | VARCHAR(32) | 暗码 | |
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 |
以下是数据库表各字段的关联关联:
完成RBAC治理的前导性事情
基于ThinkPHP完成RBAC的权限治理系统中,起首要做一些前导性的事情(系统数据库设想TP已为我们完成了),重要分以下几个方面:
• 用户(增、删、改、查)
• 角色(增、删、改、查)
• 节点(增、删、改、查)
• 设置权限(更新权限)
细致完成的代码以下(相干诠释均在解释当中):
<?php /** * */ namespace Home\Controller; use Home\Controller\BaseController; use Home\Model\AdminUserModel; use Org\Util\Tree; use Think\Page; class RbacController extends BaseController { //初始化操纵 public function _initialize() { if (!IS_AJAX) $this->error('你接见的页面不存在,请稍后再试'); } public function userIndex() { if (IS_POST) { $condition['username'] = array('like', "%" . trim(I('keybord')) . "%"); $model = D('AdminUser'); $count = $model->where($condition)->count(); $Page = new Page($count, 3); $Page->setConfig('theme', '%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%'); $show = $Page->show(); //select search $list = $model->where($condition)->field('password', true)->relation(true)->limit($Page->firstRow . ',' . $Page->listRows)->select(); $this->show = $show; $this->list = $list; $this->display('AdminUser/index'); } else { $model = D('AdminUser'); $count = $model->count(); $Page = new Page($count, 6); $Page->setConfig('header', '共%TOTAL_ROW%条'); $Page->setConfig('first', '首页'); $Page->setConfig('last', '共%TOTAL_PAGE%页'); $Page->setConfig('prev', '上一页'); $Page->setConfig('next', '下一页'); $Page->setConfig('link', 'indexpagenumb'); $Page->setConfig('theme', '%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%'); $show = $Page->show(); //select search $list = $model->field('password', true)->relation(true)->limit($Page->firstRow . ',' . $Page->listRows)->select(); $this->show = $show; $this->list = $list; $this->display('Rbac/userIndex'); } } /* * 平台用户异步考证 */ public function checkUser() { $username = trim(I('username')); $conditions = array('username' => ':username'); $result = M('AdminUser')->where($conditions)->bind(':username', $username)->find(); //假如不存在,则可以建立,也就是返回的是true if (!$result) { echo 'true'; } else { echo 'false'; } exit(); } /* * 建立平台用户,这里开启了服务器考证 */ public function createAdminUser() { if (IS_POST) { /** * [实例化User对象] * D要领实例化模子类的时刻通常是实例化某个细致的模子类,假如你仅仅是对数据表举行基础的CURD操纵的话, * 运用M要领实例化的话,由于不需要加载细致的模子类,所以机能会更高。 */ $model = D('AdminUser'); /** * 假如建立失利 示意考证没有经由历程 输出毛病提醒信息 * $model->create() 会自动挪用考证划定规矩 */ if (!$model->create()) return $this->error($model->getError()); //$username = $model->username; //$model->add() 插进去数据后会自动的摧毁数据 if (!$uid = $model->add()) return $this->success('注册失利', U('Rbac/userIndex'));//猎取用户id // 假如是注册用户的话 // session('uid', $uid); // session('username', $username); //用户增添胜利后,给用户角色表增添数据 $role['role_id'] = I('role_id'); $role['user_id'] = $uid; //增添该治理员操纵到操纵日记中 $desc = '给ID为:[' . $_POST['role_id'] . ']的角色,新增用户:[' . $_POST['username'] . '],暗码为:[' . $_POST['password'] . ']' . '其他参数' . $_POST; addOperationLog($desc); if (D('AdminRoleUser')->add($role)) { return $this->success('增添平台用户胜利', U('Rbac/userIndex')); } else { return $this->error('增添平台用户失利', U('Rbac/userIndex')); } return $this->success('增添平台用户胜利', U('Rbac/userIndex')); } $this->role_list = M('AdminRole')->select(); $this->display('Rbac/createAdminUser'); } /** * 转变用户角色 * 可以支撑不实行SQL而只是返回SQL语句:$User->fetchSql(true)->add($data); */ public function updateUser() { $userId = I('get.id'); if (IS_POST) { $data['user_id'] = I('post.user_id'); $data['role_id'] = I('post.role_id'); $model = M('AdminRoleUser'); if ($model->where(array('user_id' => $data['user_id']))->delete() == false) { return $this->error('用户角色修正失利', U('Rbac/updateUser', array('id' => $userId))); } if ($model->add($data) == false) { return $this->error('用户角色修正失利', U('Rbac/updateUser', array('id' => $userId))); } return $this->success('用户角色修正胜利', U('Rbac/userIndex')); } $this->role_list = M('AdminRole')->select(); $this->user = M('AdminUser')->join('tour_admin_role_user ON tour_admin_role_user.user_id = tour_admin_user.id')->where(array('id' => $userId))->field('user_id,username,role_id')->find(); $this->display(); } //删除用户 public function delUser() { $user_id = I('post.id', '', 'int'); $user = D('AdminUser'); $result = $user->relation(true)->where(array('id' => $user_id))->delete(); if ($result) { //增添该治理员操纵到操纵日记中 $desc = '删除用户ID:' . $user_id . '胜利'; addOperationLog($desc); $response = ['status' => 200, 'errmsg' => '删除胜利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } //增添该治理员操纵到操纵日记中 $desc = '删除用户ID:' . $user_id . '失利'; addOperationLog($desc); $response = ['status' => 500, 'errmsg' => '删除失利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } //设置用户状况 public function userStatus() { $uid = I('post.id'); $db = M('AdminUser'); $status = $db->where(array('id' => $uid))->getField('status'); $status = ($status == 1) ? 0 : 1; if ($db->where(array('id' => $uid))->setField('status', $status)) { $response = ['status' => 200, 'errmsg' => '转变胜利', 'dataList' => $status]; return $this->ajaxReturn($response, 'JSON'); } //增添该治理员操纵到操纵日记中 $desc = '设置用户状况:' . $uid . '失利'; addOperationLog($desc); $response = ['status' => 500, 'errmsg' => '转变失利', 'dataList' => $status]; return $this->ajaxReturn($response, 'JSON'); } /***********************************节点最先****************************************************/ public function nodeIndex() { $db = M('AdminNode'); $node = $db->order('id')->select(); $this->nodelist = Tree::create($node); $this->display('Rbac/nodeIndex'); } //建立权限表单处置惩罚 public function createNode() { $db = M('AdminNode'); //建立权限表单处置惩罚 if (IS_POST) { $db->create(); if (!$db->add()) { return $this->error("权限增添失利", U('Rbac/nodeIndex')); } return $this->success('权限增添胜利', U('Rbac/nodeIndex')); } $node = $db->where('level !=3')->order('sort')->select(); $this->nodelist = Tree::create($node); $this->display(); } /* * 删除权限 */ public function delNode() { $result = M('AdminNode')->where(array('id' => I('post.id', '', 'int')))->delete(); if ($result) { $response = ['status' => 200, 'errmsg' => '删除胜利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } $response = ['status' => 500, 'errmsg' => '删除失利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } /* * 设置权限状况 */ public function NodeStatus() { $id = I('post.id'); $db = M('AdminNode'); $status = $db->where(array('id' => $id))->getField('status'); $status = ($status == 1) ? 0 : 1; if ($db->where(array('id' => $id))->setField('status', $status)) { $response = ['status' => 200, 'errmsg' => '修正胜利', 'dataList' => $status]; return $this->ajaxReturn($response, 'JSON'); } $response = ['status' => 500, 'errmsg' => '修正失利', 'dataList' => $status]; return $this->ajaxReturn($response, 'JSON'); } /* * 该节点是不是在菜单栏显现 */ public function showMenus() { $id = I('post.id'); $db = M('AdminNode'); $show = $db->where(array('id' => $id))->getField('menus'); $menus = ($show == 1) ? 0 : 1; $result = $db->where(array('id' => $id))->setField('menus', $menus); if ($result) { $response = ['status' => 200, 'errmsg' => '修正胜利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } $response = ['status' => 500, 'errmsg' => '修正失利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } /***********************************角色最先****************************************************/ public function roleIndex() { $db = M('AdminRole'); $this->rolelist = $db->select(); $this->display(); } /* *建立角色 */ public function createAdminRole() { if (IS_POST) { $name = I('post.name', '', 'strip_tags'); $remark = I('post.remark', '', 'strip_tags'); $pid = I('post.pid', '', 'strip_tags'); // 用strip_tags过滤$_GET['title'] if (empty($name)) return $this->error('角色称号不能为空'); $role = M('AdminRole'); $where['name'] = ':name'; $roleName = $role->where($where)->bind(':name', $name, \PDO::PARAM_STR)->getField('name'); if ($roleName) return $this->error("角色称号:'" . $name . "'已存在", U('Rbac/roleIndex')); $role->name = $name; $role->remark = $remark; $role->pid = $pid; //create要领并不算是连接操纵,由于其返回值多是布尔值,所以必需要举行严厉推断。 if ($role->create()) { // 假如主键是自动增进型 胜利后返回值就是最新插进去的值 $result = $role->field('name,remark,pid')->add(); //假如在add要领之前挪用field要领,则示意只许可写入指定的字段数据,其他不法字段将会被过滤 if (!$result) return $this->error("角色增添失利", U('Rbac/createpartent')); return $this->success('角色增添胜利', U('Rbac/roleIndex')); } return $this->success('角色增添胜利', U('Rbac/roleIndex')); } $this->display(); } /* *增添权限Node位权限表,Access为权限-角色关联表 */ public function addNode() { $rid = I('rid', '', 'int'); if (!is_numeric($rid)) return $this->success('参数范例毛病,必需是数字', U('Rbac/roleIndex')); //getFieldById针对某个字段(ID)查询并返回某个字段(name)的值 $roleModel = M('AdminRole'); $roleWhere['id'] = ':id'; $role_name = $roleModel->where($roleWhere)->bind(':id', $rid, \PDO::PARAM_INT)->getField('name'); if ($role_name == false) return $this->success('没有找到该角色', U('Rbac/roleIndex')); //依据角色遍历一切权限 $access = M('AdminAccess'); if (IS_POST) { $actions = I('post.actions'); try { $access->startTrans(); $where['role_id'] = ':role_id'; $mod1 = $access->where($where)->bind(':role_id', $rid)->delete(); if (!$mod1) $access->rollback(); $data = array(); foreach ($actions as $value) { $tmp = explode('_', $value); $data[] = array( 'role_id' => $rid, 'node_id' => $tmp[0], 'level' => $tmp[1] ); } if (!($access->addAll($data))) { $access->rollback(); } else { $access->commit(); } return $this->success('权限设置胜利', U('Rbac/addNode', array('rid' => $rid))); } catch (\Exception $e) { $access->rollback(); return $this->success('权限设置非常', U('Rbac/addNode', array('rid' => $rid))); } } $node = M('AdminNode')->order('id')->select(); $node_list = Tree::create($node); $node_arr = array(); foreach ($node_list as $value) { $conditions['node_id'] = $value['id']; $conditions['role_id'] = $rid; $count = $access->where($conditions)->count(); if ($count) { $value['access'] = '1'; } else { $value['access'] = '0'; } $node_arr[] = $value; } $this->role_name = $role_name; $this->node_list = $node_arr; $this->rid = $rid; $this->display(); } /* *删除角色以及角色所具有的权限 */ public function delRole() { $role_id = I('post.role_id', '', 'int'); $user = D('AdminRole'); $result = $user->relation(true)->where(array('id' => $role_id))->delete(); if ($result) { $response = ['status' => 200, 'errmsg' => '修正胜利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } $response = ['status' => 500, 'errmsg' => '修正失利', 'dataList' => $result]; return $this->ajaxReturn($response, 'JSON'); } /* * 设置角色状况 */ public function roleStatus() { $rid = I('post.rid'); $db = M('AdminRole'); $status = $db->where(array('id' => $rid))->getField('status'); $status = ($status == 1) ? 0 : 1; if ($db->where(array('id' => $rid))->setField('status', $status)) { $response = ['status' => 200, 'errmsg' => '修正胜利', 'dataList' => $status]; return $this->ajaxReturn($response, 'JSON'); } $response = ['status' => 500, 'errmsg' => '修正失利', 'dataList' => $status]; return $this->ajaxReturn($response, 'JSON'); } }
ThinkPHP中RBAC类的详解
在ThinkPHP处置惩罚权限治理中,真正的难点并不是在RBAC类的运用上,上面相干的处置惩罚(权限设置,节点治理等);所以当完成以上事情,实在RBAC系统已完成了90%。下面先从ThinkPHP中RBAC的设置提及(细致请参看对应的解释内容):
<?php return array( "USER_AUTH_ON" => true, //是不是开启权限考证(必配) "USER_AUTH_TYPE" => 1, //考证体式格局(1、登录考证;2、及时考证) "USER_AUTH_KEY" => 'uid', //用户认证识别名(必配) "ADMIN_AUTH_KEY" => 'superadmin', //超等治理员识别名(必配) "USER_AUTH_MODEL" => 'user', //考证用户表模子 ly_user 'USER_AUTH_GATEWAY' => '/Public/login', //用户认证失利,跳转URL 'AUTH_PWD_ENCODER'=>'md5', //默许暗码加密体式格局 "RBAC_SUPERADMIN" => 'admin', //超等治理员称号 "NOT_AUTH_MODULE" => 'Index,Public', //无需认证的掌握器 "NOT_AUTH_ACTION" => 'index', //无需认证的要领 'REQUIRE_AUTH_MODULE' => '', //默许需要认证的模块 'REQUIRE_AUTH_ACTION' => '', //默许需要认证的行动 'GUEST_AUTH_ON' => false, //是不是开启旅客受权接见 'GUEST_AUTH_ID' => 0, //旅客标记 "RBAC_ROLE_TABLE" => 'ly_role', //角色表称号(必配) "RBAC_USER_TABLE" => 'ly_role_user', //用户角色中心表称号(必配) "RBAC_ACCESS_TABLE" => 'ly_access', //权限表称号(必配) "RBAC_NODE_TABLE" => 'ly_node', //节点表称号(必配) );
注重:
• 以上有的设置项并不是必需的,但标有“必配”,则必需设置
• 无需认证的权限和要领与需要认证的模块和行动可以依据需要选择性设置,另有部份权限相干设置并未列表出
RBAC处置惩罚类供应静态的要领
ThinkPHP的RBAC处置惩罚类供应给我们许多相干的静态要领以下:
要领名 | 吸收参数申明 | 返回值 | 申明 |
RBAC::authenticate(map,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,authId=null,module=''); | $authId:用户识别名(可不传) $module:当前操纵的模块称号 |
Array | 返回一个包括权限的ID的数组 |
RBAC::checkAccess() | 无 | 返回true或false | 搜检当前操纵是不是需要认证(依据设置中需要认证和不需要批评的模块或要领得出) |
RBAC::checkLogin() | 无 | true | 假如当前操纵需要认证且用户没有登录,继续检测是不是开启旅客受权。假如开启旅客受权,则写入旅客权限;不然跳到登录页 |
RBAC::AccessDecision($appName=APP_NAME) | $appName:选传,有默许值 | true:示意有操纵权限 false:无操纵权限 |
AccessDecision(appName=APPNAME)要领,检测当前项目模块操纵,是不是存在于appName=APPNAME)要领,检测当前项目模块操纵,是不是存在于_SESSION['_ACCESS_LIST']数组中$_SESSION['_ACCESS_LIST']['当前操纵']['当前模块']['当前操纵']是不是存在。假如存在示意有权限,返回true;不然返回flase。 |
RBAC::getAccessList($authId) | $authId:用户识别名(选传,顺序自动猎取) | Array | 经由历程数据库查询获得当前认证号的一切权限列表 |
RBAC::getModuleAccessList(authId,authId,module) | $authId:用户识别名(必)$module:对应的模块(必) | Array | 返回指定用户可接见的节点权限数组 |
注重:在运用RBAC::AccessDecision()
要领时,假如你开启了项目分组,则必需传入当前分组,代码以下:
//权限考证 if(C('USER_AUTH_ON') && !$notAuth) { import('ORG.Util.RBAC'); //运用了项目分组,则必需引入GROUP_NAME RBAC::AccessDecision(GROUP_NAME) || $this->error("你没有对应的权限"); }
RBAC处置惩罚类的现实运用
在完成用户登录,角色建立,节点增编削查的事情后,就只剩下了RBAC怎样在对应顺序代码中运用了。挻简朴的,只用在本来的代码其他上修改几个处所即可。
• 用户登录时,写入用户权限
• 用户操纵时,举行权限考证
下面是用户登录时的完成代码:
<?php namespace Home\Controller; use Think\Controller; use Org\Util\Rbac; class LoginController extends Controller { public function index() { $this->display(); } /* * 异步考证账号 */ public function checkUser() { $username = I('username'); $conditions = array('username' => ':username'); $result = M('User')->where($conditions)->bind(':username', $username)->find(); //假如不存在,则可以建立,也就是返回的是true if (!$result) { echo 'false'; } else { echo 'true'; } exit(); } /* * 异步考证暗码 */ public function checkPwd() { $username = I('post.username'); $password = I('post.password'); $conditions = array('username' => ':username'); $result = M('User')->where($conditions)->bind(':username', $username)->find(); if (md5($password) != $result['password']) { echo 'false'; } else { echo 'true'; } exit(); } /* * 搜检登录 */ public function checkLogin() { if (!IS_POST) $this->error('不法接见'); // 采纳htmlspecialchars要领对$_GET['name'] 举行过滤,假如不存在则返回空字符串 $username = I('post.username', '', 'htmlspecialchars'); // 采纳正则表达式举行变量过滤,假如正则婚配不经由历程的话,则返回默许值。 //I('get.name','','/^[A-Za-z]+$/'); $password = md5(I('post.password')); $user = D('AdminUser'); $where = array('username' => $username); $fields = array('id', 'password', 'username', 'status', 'expire', 'logintime'); // 之查找需要的字段 $result = $user->where($where)->field($fields)->find(); if (!$result || $password != $result['password']) return $this->error('账号或暗码毛病',U('Home/Login/index')); if ($result['status'] == 0) return $this->error('该用户被锁定,临时不可登录',U('Home/Login/index')); // 是不是记着我的登录,设置一个Cookie,写在客户端 if (isset($_POST['remember'])) { $value = $result['id'] . '|' . get_client_ip() . '|' . $result['username']; $value = encrytion($value, 1); @setcookie('remember', $value, C('AUTO_LOGIN_LIFETIME'), '/'); } // 天天登录增添经验值 $today = strtotime(date('Y-m-d')); // 猎取本日0时0分0秒的时刻 // 假如上次的登录时刻小于本日的时刻,则增添经验值 $where2 = array('id' => $result['id']); if ($result['logintime'] < $today) { $user->where($where2)->setInc('expire', 10); } //更新登录户登录信息 $data_arr = array( 'id' => $result['id'], 'logintime' => time(), 'loginip' => get_client_ip(), ); if ($user->save($data_arr)) { // 猎取$_SESSION['user_id'] 假如不存在则默许为0 session('uid', 0); session('username', $result['username']); session('loginAccount', $result['username']); session('loginUserName', $result['username']); session('uid', $result['id']); //RBAC 最先,用户认证SESSION标记 ,默许为"authId" session(C('USER_AUTH_KEY'), $result['id']); //假如为超等治理员,则无需考证 if ($_SESSION['username'] == C('RBAC_SUPERADMIN')) session(C('ADMIN_AUTH_KEY'), true); //用于检测用户权限的要领,并保存到Session中,读取用户权限 Rbac::saveAccessList($result['id']); //增添操纵日记中 $desc = '上岸胜利'; addOperationLog($desc); return $this->redirect('Index/index'); } else { return $this->error('2222222222222'); } } public function memberInfo() { $user_id = session('user_id'); $user = D('User'); $where = array('user_id' => $user_id); $result = $user->where($where)->select(); $this->result = $result; $this->display(); } /** * 猎取apikey_values */ public function apikey() { $secret = "6JNVkTk4jHsgF0e1oOVLwOZDeq83pDXa"; $user_id = I('user_id', '', int); // $where = array('user_id = %d ',array($user_id)); $user = M('User'); // $result = $user->where($where)->find(); $result = $user->where("user_id = %d", array($user_id))->find(); $hash = sha1($result['user_id'] . $result['password'] . $secret); $data = array( 'apikey_value' => $hash, 'apikey_time' => time() ); $where = array('user_id' => $user_id); $user->where($where)->save($data); $this->ajaxReturn($hash); } public function hash() { if (!IS_POST) { $out_data = array( 'err_msg' => 'request method is error.', 'is_success' => 'Fail' ); exit(json_encode($out_data)); }; $username = I('username'); $password = I('password'); $where = array('username' => $username); $user = M('User'); $result = $user->where($where)->find(); if (!$result || $password != $result['password']) { $out_data = array( 'err_msg' => 'Username or password is incorrect.', 'is_success' => 'Fail' ); exit(json_encode($out_data)); } /** * HASH生成划定规矩 */ $secret = "6JNVkTk4jHsgF0e1oOVLwOZDeq83pDXa"; $hash = sha1($result['user_id'] . $result['password'] . $secret); $where = array('user_id' => $result['user_id']); $data["apikey_value"] = $hash; $data["apikey_time"] = time(); $user->where($where)->save($data); $out_data = array( 'is_success' => 'Success', 'hash' => $hash ); exit(json_encode($out_data)); } public function relationTest() { echo get_client_ip(); } public function error1(){ $this->display(); } public function logout() { session('username', NULL); session_unset(); session_destroy(); return $this->redirect('Login/index'); } }
接着在掌握器目次建立一个CommonAction.class.php
文件,然后改写一切要权限考证的类,让其继续自CommonAction
。代码以下:
<?php namespace Home\Controller; use Think\Controller; use Org\Util\Rbac; class BaseController extends Controller { // /** // * ThikPHP自动运转要领,每一次,都邑自动运转这个要领 // * 要推断一个session值是不是已设置,可以运用 // session('?name'); 相当于:isset($_SESSION['name']); // */ public function _initialize(){ /***************************************网站开关****************************************************/ if(!C('WEB_STATE')) exit('网站庇护中'); /***********************************没有登录时刻时需要实行的代码**************************************/ if(!isset($_SESSION[C('USER_AUTH_KEY')])) return $this->redirect('Login/index'); /***************************************自动登录设置************************************************/ if(isset($_COOKIE['remember']) && !isset($_SESSION['uid'])){ // Cookie 解密 $value = encrytion($_COOKIE['remember']); $result = explode('|',$value); // 推断IP地点是不是一样 if($result[1] == get_client_ip()){ session('uid',$result[0]); session('uid',$result[2]); } } /***************************************权限认证****************************************************/ $Public = in_array(MODULE_NAME,explode(',',C('NOT_AUTH_MODULE'))) || in_array(ACTION_NAME,explode(',',C('NOT_AUTH_ACTION'))); // 假如不在大众模块当中,同时开启权限考证的话,则最先认证历程 if(C('USER_AUTH_ON') && !$Public) { if(!Rbac::AccessDecision()) //经由历程accessDecision猎取权限信息,true:示意有操纵权限,false:无操纵权限 { return $this->error("你没有对应的权限"); //没有猎取到权限信息时需要实行的代码 } } /***************************************导航栏菜单显现****************************************************/ /* * 思绪: * 1.掏出一切权限节点。 * 2.掏出当前登录用户具有的模块权限(取英文称号)和操纵权限(取ID) * 3.对一切权限举行遍历,先婚配模块权限,不存在删除,存在则婚配操纵权限 */ // 超等治理员登录 if(session(C('ADMIN_AUTH_KEY'))) { $menus = D('AdminNode')->where('level = 2')->relation(true)->order('sort desc')->select();//掏出一切节点 }else{ /** * [1]掏出一切的权限,是经由历程关联模子从数据库中猎取的 */ $menus = D('AdminNode')->where('level = 2')->relation(true)->order('sort desc')->select(); $module = ''; //寄存具有的模块 $node_id = ''; //寄存具有的模块 /** * [2]猎取当前用户的一切权限,这个是从RBAC中猎取的 */ $access_list = $_SESSION['_ACCESS_LIST']; //当前用户所具有的权限 foreach ($access_list as $key => $value) { foreach ($value as $key1 => $value1) { $module = $module.','.$key1; //字符串拼接模块称号 foreach ($value1 as $key2 => $value2) { $node_id = $node_id.','.$value2; //字符串拼操纵id } } } /** * [3]去除没有权限的节点,经由历程一切权限和用户已具有的权限比较 */ foreach ($menus as $key => $value) { $all_node[] = $value['name']; if(!in_array(strtoupper($value['name']), explode(',', $module))){ unset($menus[$key]); //删除模块 }else{ //模块存在,比较内里的操纵 foreach ($value['node'] as $key1 => $value1) { if(!in_array($value1['id'], explode(',', $node_id))){ unset($menus[$key]['node'][$key1]); // 删除操纵 } } } } } $this->menus = $menus; } }
在ThinkPHP
中供应了一个_initialize()
要领,是在类初始化就会实行的,也就是只需背面掌握器继续自CommonAction
类,就会在作对应操纵时,实行_initialize()
要领。
以上就是ThinkPHP中RBAC权限带菜单栏显现和细致权限操纵的细致内容,更多请关注ki4网别的相干文章!