首页 > 编程 > PHP > 正文

Thinkphp3.2.3篇:Rbac权限控制

2020-03-22 20:04:10
字体:
来源:转载
供稿:网友
  • 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


    我只能帮你这么多~~~


    PHP编程

    郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

  • 发表评论 共有条评论
    用户名: 密码:
    验证码: 匿名发表