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 <[email protected]> 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
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答