ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
~~~ <?php // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- // | Copyright (c) 2009 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st <liu21st@gmail.com> // +---------------------------------------------------------------------- // $Id: RBAC.class.php 2504 2011-12-28 07:35:29Z liu21st $ /** +------------------------------------------------------------------------------ * 基于角色的数据库方式验证类 +------------------------------------------------------------------------------ * @category ORG * @package ORG * @subpackage Util * @author liu21st <liu21st@gmail.com> * @version $Id: RBAC.class.php 2504 2011-12-28 07:35:29Z liu21st $ +------------------------------------------------------------------------------ */ // 配置文件增加设置 // ADMIN_AUTH_KEY 管理员认证SESSION标记 // USER_AUTH_KEY 用户认证SESSION标记 // // $_SESSION[C('USER_AUTH_KEY')] 用来保存登陆成功后的用户ID // $_SESSION[C('ADMIN_AUTH_KEY')] 用来保存登陆成功后的管理员ID // // USER_AUTH_ON 是否需要认证 // USER_AUTH_TYPE 认证类型,1是登陆认证,2是实时认证 // USER_AUTH_MODEL 用户模型名称 // GUEST_AUTH_ON 是否开启游客授权访问 // GUEST_AUTH_ID 游客的用户ID // // REQUIRE_AUTH_MODULE 需要认证模块(若定义了,则只验证给出的模块;否则验证所有模块) // NOT_AUTH_MODULE 无需认证模块(若定义了“需要认证模块”则本条定义无效) // REQUIRE_AUTH_ACTION 需要认证操作(若定义了,则只验证给出的操作;否则验证所有操作) // NOT_AUTH_ACTION 无需认证操作(若定义了“需要认证操作”则本条定义无效) // // USER_AUTH_GATEWAY 认证网关,如果用户没有登录则转到这页(URL路由规则) // RBAC_DB_DSN 数据库连接DSN // RBAC_ROLE_TABLE 角色表名称 // RBAC_USER_TABLE 用户表名称(应该是用户、用户组关系表) // RBAC_ACCESS_TABLE 权限表名称 // RBAC_NODE_TABLE 节点表名称 // /* -- -------------------------------------------------------- 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; */ class RBAC { // 认证方法 // 得到需要鉴别的用户列表 // 即按照map中给的条件查询用户表(由USER_AUTH_MODEL给出) static public function authenticate($map,$model='') { if(empty($model)) $model = C('USER_AUTH_MODEL'); //使用给定的Map进行认证 return M($model)->where($map)->find(); } // 用于检测用户权限的方法,并保存到Session中 // 将当前操作用户拥有的所有权限保存到$_SESSION['_ACCESS_LIST']里 // 开销巨大,是对getAccessList的封装 static function saveAccessList($authId=null) { if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')]; // 如果使用普通权限模式,保存当前用户的访问权限列表 // 对管理员开放所有权限 // 如果是实时认证(USER_AUTH_TYPE==2),则每次Decision的时候都刷新ACCESS_LIST, // 就不用在这刷新了 if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] ) $_SESSION['_ACCESS_LIST'] = RBAC::getAccessList($authId); return ; } // 取得模块的所属记录访问权限列表 返回有权限的记录ID数组 // 返回当前模块中当前用户所拥有的权限列表 // 开销巨大,是对getModuleAccessList的封装 static function getRecordAccessList($authId=null,$module='') { if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')]; if(empty($module)) $module = MODULE_NAME; //获取权限访问列表 $accessList = RBAC::getModuleAccessList($authId,$module); return $accessList; } //检查当前操作是否需要认证,需要则返回true,不需要则返回false static function checkAccess() { //如果项目要求认证,并且当前模块需要认证,则进行权限认证 if( C('USER_AUTH_ON') ){ $_module = array(); $_action = array(); if("" != C('REQUIRE_AUTH_MODULE')) { //需要认证的模块 $_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE'))); }else { //无需认证的模块 $_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE'))); } //检查当前模块是否需要认证 if((!empty($_module['no']) && !in_array(strtoupper(MODULE_NAME),$_module['no'])) || (!empty($_module['yes']) && in_array(strtoupper(MODULE_NAME),$_module['yes']))) { if("" != C('REQUIRE_AUTH_ACTION')) { //需要认证的操作 $_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION'))); }else { //无需认证的操作 $_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION'))); } //检查当前操作是否需要认证 if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) { return true; }else { return false; } }else { return false; } } return false; } // 检查用户是否登录 // 如果没有登录,则尝试进行“游客”登录;如果无法以游客身份登录,则跳转到认证网关 static public function checkLogin() { //检查当前操作是否需要认证 if(RBAC::checkAccess()) { //检查认证识别号 if(!$_SESSION[C('USER_AUTH_KEY')]) { if(C('GUEST_AUTH_ON')) { // 开启游客授权访问 if(!isset($_SESSION['_ACCESS_LIST'])) // 保存游客权限 RBAC::saveAccessList(C('GUEST_AUTH_ID')); }else{ // 禁止游客访问跳转到认证网关 redirect(PHP_FILE.C('USER_AUTH_GATEWAY')); } } } return true; } // 权限认证的过滤器方法 // 检查当前操作是否被允许,返回bool值 static public function AccessDecision($appName=APP_NAME) { //检查是否需要认证 if(RBAC::checkAccess()) { //存在认证识别号,则进行进一步的访问决策 $accessGuid = md5($appName.MODULE_NAME.ACTION_NAME); if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) { if(C('USER_AUTH_TYPE')==2) { //实时认证模式,刷新ACCESS_LIST //加强验证和即时验证模式 更加安全 后台权限修改可以即时生效 //通过数据库进行访问检查 $accessList = RBAC::getAccessList($_SESSION[C('USER_AUTH_KEY')]); }else { //登录验证模式,使用登录后填充的ACCESS_LIST // 如果是管理员或者当前操作已经认证过,无需再次认证 if( $_SESSION[$accessGuid]) { return true; } $accessList = $_SESSION['_ACCESS_LIST']; } //判断是否为组件化模式,如果是,验证其全模块名 $module = defined('P_MODULE_NAME')? P_MODULE_NAME : MODULE_NAME; if(!isset($accessList[strtoupper($appName)][strtoupper($module)][strtoupper(ACTION_NAME)])) { //没有权限 $_SESSION[$accessGuid] = false; return false; } else { $_SESSION[$accessGuid] = true; } }else{ //管理员无需认证 return true; } } return true; } /** +---------------------------------------------------------- * 取得当前认证号的所有权限列表 * (得到指定用户拥有的所有操作权限) +---------------------------------------------------------- * @param integer $authId 用户ID +---------------------------------------------------------- * @access public +---------------------------------------------------------- */ static public function getAccessList($authId) { // Db方式权限数据 $db = Db::getInstance(C('RBAC_DB_DSN')); $table = array('role'=>C('RBAC_ROLE_TABLE'), 'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'),'node'=>C('RBAC_NODE_TABLE')); // 首先检查该用户所在用户组拥有权限的所有项目 $sql = "select node.id,node.name from ". $table['role']." as role,". $table['user']." as user,". $table['access']." as access ,". $table['node']." as node ". "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"; $apps = $db->query($sql); $access = array(); foreach($apps as $key=>$app) { $appId = $app['id']; $appName = $app['name']; // 读取项目的模块权限 $access[strtoupper($appName)] = array(); // 再检查每个有权限的项目下面所有有权限的模块 $sql = "select node.id,node.name from ". $table['role']." as role,". $table['user']." as user,". $table['access']." as access ,". $table['node']." as node ". "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"; $modules = $db->query($sql); // 判断是否存在公共模块的权限 $publicAction = array(); foreach($modules as $key=>$module) { $moduleId = $module['id']; $moduleName = $module['name']; if('PUBLIC'== strtoupper($moduleName)) { $sql = "select node.id,node.name from ". $table['role']." as role,". $table['user']." as user,". $table['access']." as access ,". $table['node']." as node ". "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"; $rs = $db->query($sql); foreach ($rs as $a){ $publicAction[$a['name']] = $a['id']; } unset($modules[$key]); break; } } // 再检查每个有权限的模块(除公共模块)下面所有有权限的操作,依次读取模块的操作权限 foreach($modules as $key=>$module) { $moduleId = $module['id']; $moduleName = $module['name']; $sql = "select node.id,node.name from ". $table['role']." as role,". $table['user']." as user,". $table['access']." as access ,". $table['node']." as node ". "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"; $rs = $db->query($sql); $action = array(); foreach ($rs as $a){ $action[$a['name']] = $a['id']; } // 和公共模块的操作权限合并 $action += $publicAction; $access[strtoupper($appName)][strtoupper($moduleName)] = array_change_key_case($action,CASE_UPPER); } } return $access; } /** +---------------------------------------------------------- * 读取指定模块、指定用户拥有的所有权限列表 +---------------------------------------------------------- * @param integer $authId 用户ID * @param string $module 模块名 +---------------------------------------------------------- * @access public +---------------------------------------------------------- */// 读取指定模块、指定用户拥有的所有权限列表 static public function getModuleAccessList($authId,$module) { // Db方式 $db = Db::getInstance(C('RBAC_DB_DSN')); $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE')); $sql = "select access.node_id from ". $table['role']." as role,". $table['user']." as user,". $table['access']." as access ". "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"; $rs = $db->query($sql); $access = array(); foreach ($rs as $node){ $access[] = $node['node_id']; } return $access; } } ~~~