1.最近在深入Thinkphp,发现版本已经到了3.2.3了,很多网上下载的代码都是老版本3.1,3.0的。3.2多了命名空间,而且一些核心类库,第三方库都放在Thinkphp/Library下,早此文件夹下的子目录自动注册了命名空间。Rbac封装类放在了OrgUtilRbac.html' target='_blank'>class.php,没错,文件重新排版后我觉得清醒多了。如:
2.接下来打开这个文件哈,很复杂,大家请脑补,可参考:http://www.lyblog.net/2014/552.html
1 <?php 2 // +---------------------------------------------------------------------- 3 // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] 4 // +---------------------------------------------------------------------- 5 // | Copyright (c) 2009 http://thinkVeVb.com All rights reserved. 6 // +---------------------------------------------------------------------- 7 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) 8 // +---------------------------------------------------------------------- 9 // | Author: liu21st <liu21st@gmail.com> 10 // +---------------------------------------------------------------------- 11 namespace OrgUtil; 12 use ThinkDb; 13 /** 14 +------------------------------------------------------------------------------ 15 * 基于角色的数据库方式验证类 16 +------------------------------------------------------------------------------ 17 */ 18 // 配置文件增加设置 19 // USER_AUTH_ON 是否需要认证 20 // USER_AUTH_TYPE 认证类型 21 // USER_AUTH_KEY 认证识别号 22 // REQUIRE_AUTH_MODULE 需要认证模块 23 // NOT_AUTH_MODULE 无需认证模块 24 // USER_AUTH_GATEWAY 认证网关 25 // RBAC_DB_DSN 数据库连接DSN 26 // RBAC_ROLE_TABLE 角色表名称 27 // RBAC_USER_TABLE 用户表名称 28 // RBAC_ACCESS_TABLE 权限表名称 29 // RBAC_NODE_TABLE 节点表名称 30 /* 31 -- -------------------------------------------------------- 32 CREATE TABLE IF NOT EXISTS `think_access` ( 33 `role_id` smallint(6) unsigned NOT NULL, 34 `node_id` smallint(6) unsigned NOT NULL, 35 `level` tinyint(1) NOT NULL, 36 `module` varchar(50) DEFAULT NULL, 37 KEY `groupId` (`role_id`), 38 KEY `nodeId` (`node_id`) 39 ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 40 41 CREATE TABLE IF NOT EXISTS `think_node` ( 42 `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT, 43 `name` varchar(20) NOT NULL, 44 `title` varchar(50) DEFAULT NULL, 45 `status` tinyint(1) DEFAULT '0', 46 `remark` varchar(255) DEFAULT NULL, 47 `sort` smallint(6) unsigned DEFAULT NULL, 48 `pid` smallint(6) unsigned NOT NULL, 49 `level` tinyint(1) unsigned NOT NULL, 50 PRIMARY KEY (`id`), 51 KEY `level` (`level`), 52 KEY `pid` (`pid`), 53 KEY `status` (`status`), 54 KEY `name` (`name`) 55 ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 56 57 CREATE TABLE IF NOT EXISTS `think_role` ( 58 `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT, 59 `name` varchar(20) NOT NULL, 60 `pid` smallint(6) DEFAULT NULL, 61 `status` tinyint(1) unsigned DEFAULT NULL, 62 `remark` varchar(255) DEFAULT NULL, 63 PRIMARY KEY (`id`), 64 KEY `pid` (`pid`), 65 KEY `status` (`status`) 66 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; 67 68 CREATE TABLE IF NOT EXISTS `think_role_user` ( 69 `role_id` mediumint(9) unsigned DEFAULT NULL, 70 `user_id` char(32) DEFAULT NULL, 71 KEY `group_id` (`role_id`), 72 KEY `user_id` (`user_id`) 73 ) ENGINE=MyISAM DEFAULT CHARSET=utf8; 74 */ 75 class Rbac { 76 // 认证方法 77 static public function authenticate($map,$model='') { 78 if(empty($model)) $model = C('USER_AUTH_MODEL'); 79 //使用给定的Map进行认证 80 return M($model)->where($map)->find(); 81 } 82 83 //用于检测用户权限的方法,并保存到Session中 84 static function saveAccessList($authId=null) { 85 if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')]; 86 // 如果使用普通权限模式,保存当前用户的访问权限列表 87 // 对管理员开发所有权限 88 if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] ) 89 $_SESSION['_ACCESS_LIST'] = self::getAccessList($authId); 90 return ; 91 } 92 93 // 取得模块的所属记录访问权限列表 返回有权限的记录ID数组 94 static function getRecordAccessList($authId=null,$module='') { 95 if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')]; 96 if(empty($module)) $module = CONTROLLER_NAME; 97 //获取权限访问列表 98 $accessList = self::getModuleAccessList($authId,$module); 99 return $accessList;100 }101 102 //检查当前操作是否需要认证103 static function checkAccess() {104 //如果项目要求认证,并且当前模块需要认证,则进行权限认证105 if( C('USER_AUTH_ON') ){106 $_module = array();107 $_action = array();108 if('' != C('REQUIRE_AUTH_MODULE')) {109 //需要认证的模块110 $_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE')));111 }else {112 //无需认证的模块113 $_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE')));114 }115 //检查当前模块是否需要认证116 if((!empty($_module['no']) && !in_array(strtoupper(CONTROLLER_NAME),$_module['no'])) || (!empty($_module['yes']) && in_array(strtoupper(CONTROLLER_NAME),$_module['yes']))) {117 if('' != C('REQUIRE_AUTH_ACTION')) {118 //需要认证的操作119 $_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION')));120 }else {121 //无需认证的操作122 $_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION')));123 }124 //检查当前操作是否需要认证125 if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) {126 return true;127 }else {128 return false;129 }130 }else {131 return false;132 }133 }134 return false;135 }136 137 // 登录检查138 static public function checkLogin() {139 //检查当前操作是否需要认证140 if(self::checkAccess()) {141 //检查认证识别号142 if(!$_SESSION[C('USER_AUTH_KEY')]) {143 if(C('GUEST_AUTH_ON')) {144 // 开启游客授权访问145 if(!isset($_SESSION['_ACCESS_LIST']))146 // 保存游客权限147 self::saveAccessList(C('GUEST_AUTH_ID'));148 }else{149 // 禁止游客访问跳转到认证网关150 redirect(PHP_FILE.C('USER_AUTH_GATEWAY'));151 }152 }153 }154 return true;155 }156 157 //权限认证的过滤器方法158 static public function AccessDecision($appName=MODULE_NAME) {159 //检查是否需要认证160 if(self::checkAccess()) {161 //存在认证识别号,则进行进一步的访问决策162 $accessGuid = md5($appName.CONTROLLER_NAME.ACTION_NAME); //可以访问的session163 if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) {164 if(C('USER_AUTH_TYPE')==2) {165 //加强验证和即时验证模式 更加安全 后台权限修改可以即时生效166 //通过数据库进行访问检查167 $accessList = self::getAccessList($_SESSION[C('USER_AUTH_KEY')]);168 }else {169 // 如果是管理员或者当前操作已经认证过,无需再次认证170 if( $_SESSION[$accessGuid]) {171 return true;172 }173 //登录验证模式,比较登录后保存的权限访问列表174 $accessList = $_SESSION['_ACCESS_LIST'];175 }176 //判断是否为组件化模式,如果是,验证其全模块名177 if(!isset($accessList[strtoupper($appName)][strtoupper(CONTROLLER_NAME)][strtoupper(ACTION_NAME)])) {178 $_SESSION[$accessGuid] = false;179 return false;180 }181 else {182 $_SESSION[$accessGuid] = true;183 }184 }else{185 //管理员无需认证186 return true;187 }188 }189 return true;190 }191 192 /**193 +----------------------------------------------------------194 * 取得当前认证号的所有权限列表195 +----------------------------------------------------------196 * @param integer $authId 用户ID197 +----------------------------------------------------------198 * @access public199 +----------------------------------------------------------200 */201 static public function getAccessList($authId) {202 // Db方式权限数据203 $db = Db::getInstance(C('RBAC_DB_DSN'));204 $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'),'node'=>C('RBAC_NODE_TABLE'));205 $sql = 'select node.id,node.name from '.206 $table['role'].' as role,'.207 $table['user'].' as user,'.208 $table['access'].' as access ,'.209 $table['node'].' as node '.210 'where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=1 and node.status=1';211 $apps = $db->query($sql);212 $access = array();213 foreach($apps as $key=>$app) {214 $appId = $app['id'];215 $appName = $app['name'];216 // 读取项目的模块权限217 $access[strtoupper($appName)] = array();218 $sql = 'select node.id,node.name from '.219 $table['role'].' as role,'.220 $table['user'].' as user,'.221 $table['access'].' as access ,'.222 $table['node'].' as node '.223 'where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=2 and node.pid={$appId} and node.status=1';224 $modules = $db->query($sql);225 // 判断是否存在公共模块的权限226 $publicAction = array();227 foreach($modules as $key=>$module) {228 $moduleId = $module['id'];229 $moduleName = $module['name'];230 if('PUBLIC'== strtoupper($moduleName)) {231 $sql = 'select node.id,node.name from '.232 $table['role'].' as role,'.233 $table['user'].' as user,'.234 $table['access'].' as access ,'.235 $table['node'].' as node '.236 'where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1';237 $rs = $db->query($sql);238 foreach ($rs as $a){239 $publicAction[$a['name']] = $a['id'];240 }241 unset($modules[$key]);242 break;243 }244 }245 // 依次读取模块的操作权限246 foreach($modules as $key=>$module) {247 $moduleId = $module['id'];248 $moduleName = $module['name'];249 $sql = 'select node.id,node.name from '.250 $table['role'].' as role,'.251 $table['user'].' as user,'.252 $table['access'].' as access ,'.253 $table['node'].' as node '.254 'where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.node_id=node.id and node.level=3 and node.pid={$moduleId} and node.status=1';255 $rs = $db->query($sql);256 $action = array();257 foreach ($rs as $a){258 $action[$a['name']] = $a['id'];259 }260 // 和公共模块的操作权限合并261 $action += $publicAction;262 $access[strtoupper($appName)][strtoupper($moduleName)] = array_change_key_case($action,CASE_UPPER);263 }264 }265 return $access;266 }267 268 // 读取模块所属的记录访问权限269 static public function getModuleAccessList($authId,$module) {270 // Db方式271 $db = Db::getInstance(C('RBAC_DB_DSN'));272 $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'));273 $sql = 'select access.node_id from '.274 $table['role'].' as role,'.275 $table['user'].' as user,'.276 $table['access'].' as access '.277 'where user.user_id='{$authId}' and user.role_id=role.id and ( access.role_id=role.id or (access.role_id=role.pid and role.pid!=0 ) ) and role.status=1 and access.module='{$module}' and access.status=1';278 $rs = $db->query($sql);279 $access = array();280 foreach ($rs as $node){281 $access[] = $node['node_id'];282 }283 return $access;284 }285 }
3.在你的配置文件中,如Application/Common/Config/config.php或者模块下的Application/Admin/Config/config.php下补入:
1 'USER_AUTH_ON' => true, // 支持权限检查? 2 'USER_AUTH_TYPE' => 1, // 默认认证类型 1 登录认证 2 实时认证 3 'USER_AUTH_KEY' => 'authId', // 用户认证SESSION标记 4 'ADMIN_AUTH_KEY' => 'administrator', // session里有这个管理员不需要认证 5 'ADMINISTRATOR' => 'admin', 6 'USER_AUTH_MODEL' => 'User', // 默认验证数据表模型 7 'AUTH_PWD_ENCODER' => 'md5', // 用户认证密码加密方式 8 'USER_AUTH_GATEWAY' => '/Public/login', // 默认认证网关 9 'NOT_AUTH_MODULE' => 'Public', // 默认无需认证模块10 'REQUIRE_AUTH_MODULE' => '', // 默认需要认证模块11 'NOT_AUTH_ACTION' => '', // 默认无需认证操作12 'REQUIRE_AUTH_ACTION' => '', // 默认需要认证操作13 'GUEST_AUTH_ON' => false, // 是否开启游客授权访问14 'GUEST_AUTH_ID' => 0, // 游客的用户ID15 16 'RBAC_ERROR_PAGE' => '/thinkphps/Public/error404.html'
4.建一个公共控制器,如CommomController.class.php,里面有个构造函数进行权限验证。然后呢,其他控制器都继承它,这样都行了。或者可以在行为里面定义,然后监听,这个我就不贴了。如:
<?php// @function 公共控制器namespace AdminController;use ThinkController;class CommonController extends Controller { function _initialize() { // 用户权限检查 if (C ( 'USER_AUTH_ON' ) && ! in_array ( MODULE_NAME, explode ( ',', C ( 'NOT_AUTH_MODULE' ) ) )) { //1.如果需要验证 if (! OrgUtilRbac::AccessDecision ()) { // 2.没有登陆 if (! $_SESSION [C ( 'USER_AUTH_KEY' )]) { // 3.游客可访问 if(C('GUEST_AUTH_ON')) { // 4.游客授权 if(!isset($_SESSION['_ACCESS_LIST'])) // 保存游客权限 OrgUtilRbac::saveAccessList(C('GUEST_AUTH_ID')); }else{ // 5.无登陆,禁止游客访问,无权限页面 $this->error ( L ( '_VALID_ACCESS_' ) ); } } // 6.登陆,没有权限, 如果有错误页面则定向 if (C ( 'RBAC_ERROR_PAGE' )) { // 定义权限错误页面 redirect ( C ( 'RBAC_ERROR_PAGE' ) ); } //7.没有定义错误页面定向,跳到登陆页面 else{ redirect(PHP_FILE.C('USER_AUTH_GATEWAY')); } } } }
5.具体验证的过程已经在上述给出,大家可以吐槽我。
这个Rbac,基于角色访问控制还挺麻烦的,因为你要写Node数据表规定那个操作不能访问,要写很多哦,而且开启游客访问,游客ID是0,你也要手动写进去。
听说还有一种Auth验证什么的。
6.不要问我这是什么,请脑补:
L ( '_VALID_ACCESS_' ) ;
PHP_FILE
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
新闻热点
疑难解答