PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/xianpipa/ThinkPHP/Library/Org/Util/Rbac.class.php

https://gitlab.com/fangfangchen/xianpipa
PHP | 285 lines | 161 code | 7 blank | 117 comment | 30 complexity | e78862dbf33a2732e20bc3ba98d30bee MD5 | raw file
  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. CREATE TABLE IF NOT EXISTS `think_node` (
  41. `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  42. `name` varchar(20) NOT NULL,
  43. `title` varchar(50) DEFAULT NULL,
  44. `status` tinyint(1) DEFAULT '0',
  45. `remark` varchar(255) DEFAULT NULL,
  46. `sort` smallint(6) unsigned DEFAULT NULL,
  47. `pid` smallint(6) unsigned NOT NULL,
  48. `level` tinyint(1) unsigned NOT NULL,
  49. PRIMARY KEY (`id`),
  50. KEY `level` (`level`),
  51. KEY `pid` (`pid`),
  52. KEY `status` (`status`),
  53. KEY `name` (`name`)
  54. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  55. CREATE TABLE IF NOT EXISTS `think_role` (
  56. `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  57. `name` varchar(20) NOT NULL,
  58. `pid` smallint(6) DEFAULT NULL,
  59. `status` tinyint(1) unsigned DEFAULT NULL,
  60. `remark` varchar(255) DEFAULT NULL,
  61. PRIMARY KEY (`id`),
  62. KEY `pid` (`pid`),
  63. KEY `status` (`status`)
  64. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
  65. CREATE TABLE IF NOT EXISTS `think_role_user` (
  66. `role_id` mediumint(9) unsigned DEFAULT NULL,
  67. `user_id` char(32) DEFAULT NULL,
  68. KEY `group_id` (`role_id`),
  69. KEY `user_id` (`user_id`)
  70. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  71. */
  72. class Rbac {
  73. // 认证方法
  74. static public function authenticate($map,$model='') {
  75. if(empty($model)) $model = C('USER_AUTH_MODEL');
  76. //使用给定的Map进行认证
  77. return M($model)->where($map)->find();
  78. }
  79. //用于检测用户权限的方法,并保存到Session中
  80. static function saveAccessList($authId=null) {
  81. if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')];
  82. // 如果使用普通权限模式,保存当前用户的访问权限列表
  83. // 对管理员开发所有权限
  84. if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] )
  85. $_SESSION['_ACCESS_LIST'] = self::getAccessList($authId);
  86. return ;
  87. }
  88. // 取得模块的所属记录访问权限列表 返回有权限的记录ID数组
  89. static function getRecordAccessList($authId=null,$module='') {
  90. if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')];
  91. if(empty($module)) $module = CONTROLLER_NAME;
  92. //获取权限访问列表
  93. $accessList = self::getModuleAccessList($authId,$module);
  94. return $accessList;
  95. }
  96. //检查当前操作是否需要认证
  97. static function checkAccess() {
  98. //如果项目要求认证,并且当前模块需要认证,则进行权限认证
  99. if( C('USER_AUTH_ON') ){
  100. $_module = array();
  101. $_action = array();
  102. if("" != C('REQUIRE_AUTH_MODULE')) {
  103. //需要认证的模块
  104. $_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE')));
  105. }else {
  106. //无需认证的模块
  107. $_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE')));
  108. }
  109. //检查当前模块是否需要认证
  110. if((!empty($_module['no']) && !in_array(strtoupper(CONTROLLER_NAME),$_module['no'])) || (!empty($_module['yes']) && in_array(strtoupper(CONTROLLER_NAME),$_module['yes']))) {
  111. if("" != C('REQUIRE_AUTH_ACTION')) {
  112. //需要认证的操作
  113. $_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION')));
  114. }else {
  115. //无需认证的操作
  116. $_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION')));
  117. }
  118. //检查当前操作是否需要认证
  119. if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) {
  120. return true;
  121. }else {
  122. return false;
  123. }
  124. }else {
  125. return false;
  126. }
  127. }
  128. return false;
  129. }
  130. // 登录检查
  131. static public function checkLogin() {
  132. //检查当前操作是否需要认证
  133. if(self::checkAccess()) {
  134. //检查认证识别号
  135. if(!$_SESSION[C('USER_AUTH_KEY')]) {
  136. if(C('GUEST_AUTH_ON')) {
  137. // 开启游客授权访问
  138. if(!isset($_SESSION['_ACCESS_LIST']))
  139. // 保存游客权限
  140. self::saveAccessList(C('GUEST_AUTH_ID'));
  141. }else{
  142. // 禁止游客访问跳转到认证网关
  143. redirect(PHP_FILE.C('USER_AUTH_GATEWAY'));
  144. }
  145. }
  146. }
  147. return true;
  148. }
  149. //权限认证的过滤器方法
  150. static public function AccessDecision($appName=MODULE_NAME) {
  151. //检查是否需要认证
  152. if(self::checkAccess()) {
  153. //存在认证识别号,则进行进一步的访问决策
  154. $accessGuid = md5($appName.CONTROLLER_NAME.ACTION_NAME);
  155. if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) {
  156. if(C('USER_AUTH_TYPE')==2) {
  157. //加强验证和即时验证模式 更加安全 后台权限修改可以即时生效
  158. //通过数据库进行访问检查
  159. $accessList = self::getAccessList($_SESSION[C('USER_AUTH_KEY')]);
  160. }else {
  161. // 如果是管理员或者当前操作已经认证过,无需再次认证
  162. if( $_SESSION[$accessGuid]) {
  163. return true;
  164. }
  165. //登录验证模式,比较登录后保存的权限访问列表
  166. $accessList = $_SESSION['_ACCESS_LIST'];
  167. }
  168. //判断是否为组件化模式,如果是,验证其全模块名
  169. if(!isset($accessList[strtoupper($appName)][strtoupper(CONTROLLER_NAME)][strtoupper(ACTION_NAME)])) {
  170. $_SESSION[$accessGuid] = false;
  171. return false;
  172. }
  173. else {
  174. $_SESSION[$accessGuid] = true;
  175. }
  176. }else{
  177. //管理员无需认证
  178. return true;
  179. }
  180. }
  181. return true;
  182. }
  183. /**
  184. +----------------------------------------------------------
  185. * 取得当前认证号的所有权限列表
  186. +----------------------------------------------------------
  187. * @param integer $authId 用户ID
  188. +----------------------------------------------------------
  189. * @access public
  190. +----------------------------------------------------------
  191. */
  192. static public function getAccessList($authId) {
  193. // Db方式权限数据
  194. $db = Db::getInstance(C('RBAC_DB_DSN'));
  195. $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'),'node'=>C('RBAC_NODE_TABLE'));
  196. $sql = "select node.id,node.name from ".
  197. $table['role']." as role,".
  198. $table['user']." as user,".
  199. $table['access']." as access ,".
  200. $table['node']." as node ".
  201. "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";
  202. $apps = $db->query($sql);
  203. $access = array();
  204. foreach($apps as $key=>$app) {
  205. $appId = $app['id'];
  206. $appName = $app['name'];
  207. // 读取项目的模块权限
  208. $access[strtoupper($appName)] = array();
  209. $sql = "select node.id,node.name from ".
  210. $table['role']." as role,".
  211. $table['user']." as user,".
  212. $table['access']." as access ,".
  213. $table['node']." as node ".
  214. "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";
  215. $modules = $db->query($sql);
  216. // 判断是否存在公共模块的权限
  217. $publicAction = array();
  218. foreach($modules as $key=>$module) {
  219. $moduleId = $module['id'];
  220. $moduleName = $module['name'];
  221. if('PUBLIC'== strtoupper($moduleName)) {
  222. $sql = "select node.id,node.name from ".
  223. $table['role']." as role,".
  224. $table['user']." as user,".
  225. $table['access']." as access ,".
  226. $table['node']." as node ".
  227. "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";
  228. $rs = $db->query($sql);
  229. foreach ($rs as $a){
  230. $publicAction[$a['name']] = $a['id'];
  231. }
  232. unset($modules[$key]);
  233. break;
  234. }
  235. }
  236. // 依次读取模块的操作权限
  237. foreach($modules as $key=>$module) {
  238. $moduleId = $module['id'];
  239. $moduleName = $module['name'];
  240. $sql = "select node.id,node.name from ".
  241. $table['role']." as role,".
  242. $table['user']." as user,".
  243. $table['access']." as access ,".
  244. $table['node']." as node ".
  245. "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";
  246. $rs = $db->query($sql);
  247. $action = array();
  248. foreach ($rs as $a){
  249. $action[$a['name']] = $a['id'];
  250. }
  251. // 和公共模块的操作权限合并
  252. $action += $publicAction;
  253. $access[strtoupper($appName)][strtoupper($moduleName)] = array_change_key_case($action,CASE_UPPER);
  254. }
  255. }
  256. return $access;
  257. }
  258. // 读取模块所属的记录访问权限
  259. static public function getModuleAccessList($authId,$module) {
  260. // Db方式
  261. $db = Db::getInstance(C('RBAC_DB_DSN'));
  262. $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'));
  263. $sql = "select access.node_id from ".
  264. $table['role']." as role,".
  265. $table['user']." as user,".
  266. $table['access']." as access ".
  267. "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";
  268. $rs = $db->query($sql);
  269. $access = array();
  270. foreach ($rs as $node){
  271. $access[] = $node['node_id'];
  272. }
  273. return $access;
  274. }
  275. }