Rbac.class.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <?php
  2. /**
  3. * 洛阳赤炎鹰网络科技有限公司
  4. * https://www.cyyvip.com
  5. * Copyright (c) 2022 赤店商城 All rights reserved.
  6. */
  7. // +----------------------------------------------------------------------
  8. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  9. // +----------------------------------------------------------------------
  10. // | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
  11. // +----------------------------------------------------------------------
  12. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  13. // +----------------------------------------------------------------------
  14. // | Author: liu21st <liu21st@gmail.com>
  15. // +----------------------------------------------------------------------
  16. namespace Org\Util;
  17. use Think\Db;
  18. /**
  19. +------------------------------------------------------------------------------
  20. * 基于角色的数据库方式验证类
  21. +------------------------------------------------------------------------------
  22. */
  23. // 配置文件增加设置
  24. // USER_AUTH_ON 是否需要认证
  25. // USER_AUTH_TYPE 认证类型
  26. // USER_AUTH_KEY 认证识别号
  27. // REQUIRE_AUTH_MODULE 需要认证模块
  28. // NOT_AUTH_MODULE 无需认证模块
  29. // USER_AUTH_GATEWAY 认证网关
  30. // RBAC_DB_DSN 数据库连接DSN
  31. // RBAC_ROLE_TABLE 角色表名称
  32. // RBAC_USER_TABLE 用户表名称
  33. // RBAC_ACCESS_TABLE 权限表名称
  34. // RBAC_NODE_TABLE 节点表名称
  35. /*
  36. -- --------------------------------------------------------
  37. CREATE TABLE IF NOT EXISTS `think_access` (
  38. `role_id` smallint(6) unsigned NOT NULL,
  39. `node_id` smallint(6) unsigned NOT NULL,
  40. `level` tinyint(1) NOT NULL,
  41. `module` varchar(50) DEFAULT NULL,
  42. KEY `groupId` (`role_id`),
  43. KEY `nodeId` (`node_id`)
  44. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  45. CREATE TABLE IF NOT EXISTS `think_node` (
  46. `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  47. `name` varchar(20) NOT NULL,
  48. `title` varchar(50) DEFAULT NULL,
  49. `status` tinyint(1) DEFAULT '0',
  50. `remark` varchar(255) DEFAULT NULL,
  51. `sort` smallint(6) unsigned DEFAULT NULL,
  52. `pid` smallint(6) unsigned NOT NULL,
  53. `level` tinyint(1) unsigned NOT NULL,
  54. PRIMARY KEY (`id`),
  55. KEY `level` (`level`),
  56. KEY `pid` (`pid`),
  57. KEY `status` (`status`),
  58. KEY `name` (`name`)
  59. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  60. CREATE TABLE IF NOT EXISTS `think_role` (
  61. `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT,
  62. `name` varchar(20) NOT NULL,
  63. `pid` smallint(6) DEFAULT NULL,
  64. `status` tinyint(1) unsigned DEFAULT NULL,
  65. `remark` varchar(255) DEFAULT NULL,
  66. PRIMARY KEY (`id`),
  67. KEY `pid` (`pid`),
  68. KEY `status` (`status`)
  69. ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
  70. CREATE TABLE IF NOT EXISTS `think_role_user` (
  71. `role_id` mediumint(9) unsigned DEFAULT NULL,
  72. `user_id` char(32) DEFAULT NULL,
  73. KEY `group_id` (`role_id`),
  74. KEY `user_id` (`user_id`)
  75. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  76. */
  77. class Rbac {
  78. // 认证方法
  79. static public function authenticate($map,$model='') {
  80. if(empty($model)) $model = C('USER_AUTH_MODEL');
  81. //使用给定的Map进行认证
  82. return M($model)->where($map)->find();
  83. }
  84. //用于检测用户权限的方法,并保存到Session中
  85. static function saveAccessList($authId=null) {
  86. if(null===$authId) $authId = $_SESSION[C('USER_AUTH_KEY')];
  87. // 如果使用普通权限模式,保存当前用户的访问权限列表
  88. // 对管理员开发所有权限
  89. if(C('USER_AUTH_TYPE') !=2 && !$_SESSION[C('ADMIN_AUTH_KEY')] )
  90. $_SESSION['_ACCESS_LIST'] = self::getAccessList($authId);
  91. return ;
  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. static function checkAccess() {
  103. //如果项目要求认证,并且当前模块需要认证,则进行权限认证
  104. if( C('USER_AUTH_ON') ){
  105. $_module = array();
  106. $_action = array();
  107. if("" != C('REQUIRE_AUTH_MODULE')) {
  108. //需要认证的模块
  109. $_module['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_MODULE')));
  110. }else {
  111. //无需认证的模块
  112. $_module['no'] = explode(',',strtoupper(C('NOT_AUTH_MODULE')));
  113. }
  114. //检查当前模块是否需要认证
  115. if((!empty($_module['no']) && !in_array(strtoupper(CONTROLLER_NAME),$_module['no'])) || (!empty($_module['yes']) && in_array(strtoupper(CONTROLLER_NAME),$_module['yes']))) {
  116. if("" != C('REQUIRE_AUTH_ACTION')) {
  117. //需要认证的操作
  118. $_action['yes'] = explode(',',strtoupper(C('REQUIRE_AUTH_ACTION')));
  119. }else {
  120. //无需认证的操作
  121. $_action['no'] = explode(',',strtoupper(C('NOT_AUTH_ACTION')));
  122. }
  123. //检查当前操作是否需要认证
  124. if((!empty($_action['no']) && !in_array(strtoupper(ACTION_NAME),$_action['no'])) || (!empty($_action['yes']) && in_array(strtoupper(ACTION_NAME),$_action['yes']))) {
  125. return true;
  126. }else {
  127. return false;
  128. }
  129. }else {
  130. return false;
  131. }
  132. }
  133. return false;
  134. }
  135. // 登录检查
  136. static public function checkLogin() {
  137. //检查当前操作是否需要认证
  138. if(self::checkAccess()) {
  139. //检查认证识别号
  140. if(!$_SESSION[C('USER_AUTH_KEY')]) {
  141. if(C('GUEST_AUTH_ON')) {
  142. // 开启游客授权访问
  143. if(!isset($_SESSION['_ACCESS_LIST']))
  144. // 保存游客权限
  145. self::saveAccessList(C('GUEST_AUTH_ID'));
  146. }else{
  147. // 禁止游客访问跳转到认证网关
  148. redirect(PHP_FILE.C('USER_AUTH_GATEWAY'));
  149. }
  150. }
  151. }
  152. return true;
  153. }
  154. //权限认证的过滤器方法
  155. static public function AccessDecision($appName=MODULE_NAME) {
  156. //检查是否需要认证
  157. if(self::checkAccess()) {
  158. //存在认证识别号,则进行进一步的访问决策
  159. $accessGuid = md5($appName.CONTROLLER_NAME.ACTION_NAME);
  160. if(empty($_SESSION[C('ADMIN_AUTH_KEY')])) {
  161. if(C('USER_AUTH_TYPE')==2) {
  162. //加强验证和即时验证模式 更加安全 后台权限修改可以即时生效
  163. //通过数据库进行访问检查
  164. $accessList = self::getAccessList($_SESSION[C('USER_AUTH_KEY')]);
  165. }else {
  166. // 如果是管理员或者当前操作已经认证过,无需再次认证
  167. if( $_SESSION[$accessGuid]) {
  168. return true;
  169. }
  170. //登录验证模式,比较登录后保存的权限访问列表
  171. $accessList = $_SESSION['_ACCESS_LIST'];
  172. }
  173. //判断是否为组件化模式,如果是,验证其全模块名
  174. if(!isset($accessList[strtoupper($appName)][strtoupper(CONTROLLER_NAME)][strtoupper(ACTION_NAME)])) {
  175. $_SESSION[$accessGuid] = false;
  176. return false;
  177. }
  178. else {
  179. $_SESSION[$accessGuid] = true;
  180. }
  181. }else{
  182. //管理员无需认证
  183. return true;
  184. }
  185. }
  186. return true;
  187. }
  188. /**
  189. +----------------------------------------------------------
  190. * 取得当前认证号的所有权限列表
  191. +----------------------------------------------------------
  192. * @param integer $authId 用户ID
  193. +----------------------------------------------------------
  194. * @access public
  195. +----------------------------------------------------------
  196. */
  197. static public function getAccessList($authId) {
  198. // Db方式权限数据
  199. $db = Db::getInstance(C('RBAC_DB_DSN'));
  200. $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'),'node'=>C('RBAC_NODE_TABLE'));
  201. $sql = "select node.id,node.name from ".
  202. $table['role']." as role,".
  203. $table['user']." as user,".
  204. $table['access']." as access ,".
  205. $table['node']." as node ".
  206. "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";
  207. $apps = $db->query($sql);
  208. $access = array();
  209. foreach($apps as $key=>$app) {
  210. $appId = $app['id'];
  211. $appName = $app['name'];
  212. // 读取项目的模块权限
  213. $access[strtoupper($appName)] = array();
  214. $sql = "select node.id,node.name from ".
  215. $table['role']." as role,".
  216. $table['user']." as user,".
  217. $table['access']." as access ,".
  218. $table['node']." as node ".
  219. "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";
  220. $modules = $db->query($sql);
  221. // 判断是否存在公共模块的权限
  222. $publicAction = array();
  223. foreach($modules as $key=>$module) {
  224. $moduleId = $module['id'];
  225. $moduleName = $module['name'];
  226. if('PUBLIC'== strtoupper($moduleName)) {
  227. $sql = "select node.id,node.name from ".
  228. $table['role']." as role,".
  229. $table['user']." as user,".
  230. $table['access']." as access ,".
  231. $table['node']." as node ".
  232. "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";
  233. $rs = $db->query($sql);
  234. foreach ($rs as $a){
  235. $publicAction[$a['name']] = $a['id'];
  236. }
  237. unset($modules[$key]);
  238. break;
  239. }
  240. }
  241. // 依次读取模块的操作权限
  242. foreach($modules as $key=>$module) {
  243. $moduleId = $module['id'];
  244. $moduleName = $module['name'];
  245. $sql = "select node.id,node.name from ".
  246. $table['role']." as role,".
  247. $table['user']." as user,".
  248. $table['access']." as access ,".
  249. $table['node']." as node ".
  250. "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";
  251. $rs = $db->query($sql);
  252. $action = array();
  253. foreach ($rs as $a){
  254. $action[$a['name']] = $a['id'];
  255. }
  256. // 和公共模块的操作权限合并
  257. $action += $publicAction;
  258. $access[strtoupper($appName)][strtoupper($moduleName)] = array_change_key_case($action,CASE_UPPER);
  259. }
  260. }
  261. return $access;
  262. }
  263. // 读取模块所属的记录访问权限
  264. static public function getModuleAccessList($authId,$module) {
  265. // Db方式
  266. $db = Db::getInstance(C('RBAC_DB_DSN'));
  267. $table = array('role'=>C('RBAC_ROLE_TABLE'),'user'=>C('RBAC_USER_TABLE'),'access'=>C('RBAC_ACCESS_TABLE'));
  268. $sql = "select access.node_id from ".
  269. $table['role']." as role,".
  270. $table['user']." as user,".
  271. $table['access']." as access ".
  272. "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";
  273. $rs = $db->query($sql);
  274. $access = array();
  275. foreach ($rs as $node){
  276. $access[] = $node['node_id'];
  277. }
  278. return $access;
  279. }
  280. }