转载

Thinkphp3.2.3篇:Rbac权限控制

1.最近在深入Thinkphp,发现版本已经到了3.2.3了,很多网上下载的代码都是老版本3.1,3.0的。3.2多了命名空间,而且一些核心类库,第三方库都放在Thinkphp/Library下,早此文件夹下的子目录自动注册了命名空间。Rbac封装类放在了/Org/Util/Rbac.class.php,没错,文件重新排版后我觉得清醒多了。如:

Thinkphp3.2.3篇:Rbac权限控制

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://thinkphp.cn All rights reserved.   6 // +----------------------------------------------------------------------   7 // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )   8 // +----------------------------------------------------------------------   9 // | Author: liu21st <liu21st@gmail.com>  10 // +----------------------------------------------------------------------  11 namespace Org/Util;  12 use Think/Db;  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);    //可以访问的session 163             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 用户ID 197      +---------------------------------------------------------- 198      * @access public 199      +---------------------------------------------------------- 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, // 游客的用户ID 15          16         'RBAC_ERROR_PAGE' => '/thinkphps/Public/error404.html'

4.建一个公共控制器,如CommomController.class.php,里面有个构造函数进行权限验证。然后呢,其他控制器都继承它,这样都行了。或者可以在行为里面定义,然后监听,这个我就不贴了。如:

<?php // @function 公共控制器 namespace Admin/Controller; use Think/Controller; class CommonController extends Controller {  function _initialize() {   // 用户权限检查   if (C ( 'USER_AUTH_ON' ) && ! in_array ( MODULE_NAME, explode ( ',', C ( 'NOT_AUTH_MODULE' ) ) )) {    //1.如果需要验证    if (! /Org/Util/Rbac::AccessDecision ()) {     // 2.没有登陆     if (! $_SESSION [C ( 'USER_AUTH_KEY' )]) {      // 3.游客可访问       if(C('GUEST_AUTH_ON')) {        // 4.游客授权        if(!isset($_SESSION['_ACCESS_LIST']))         // 保存游客权限          /Org/Util/Rbac::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


Thinkphp3.2.3篇:Rbac权限控制

我只能帮你这么多~~~


正文到此结束
Loading...