Rbac.class.php
12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
<?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>
// +----------------------------------------------------------------------
namespace Org\Util;
use Think\Db;
/**
* +------------------------------------------------------------------------------
* 基于角色的数据库方式验证类
* +------------------------------------------------------------------------------
*/
// 配置文件增加设置
// USER_AUTH_ON 是否需要认证
// USER_AUTH_TYPE 认证类型
// USER_AUTH_KEY 认证识别号
// REQUIRE_AUTH_MODULE 需要认证模块
// NOT_AUTH_MODULE 无需认证模块
// USER_AUTH_GATEWAY 认证网关
// 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
{
// 认证方法
static public function authenticate($map, $model = '')
{
if (empty($model)) {
$model = C('USER_AUTH_MODEL');
}
// 使用给定的Map进行认证
return M($model)->where($map)->find();
}
// 用于检测用户权限的方法,并保存到Session中
static function saveAccessList($authId = null)
{
if (null === $authId) {
$authId = $_SESSION[C('USER_AUTH_KEY')];
}
// 如果使用普通权限模式,保存当前用户的访问权限列表
// 对管理员开发所有权限
if (C('USER_AUTH_TYPE') != 2 && ! $_SESSION[C('ADMIN_AUTH_KEY')]) {
$_SESSION['_ACCESS_LIST'] = self::getAccessList($authId);
}
return;
}
// 取得模块的所属记录访问权限列表 返回有权限的记录ID数组
static function getRecordAccessList($authId = null, $module = '')
{
if (null === $authId) {
$authId = $_SESSION[C('USER_AUTH_KEY')];
}
if (empty($module)) {
$module = CONTROLLER_NAME;
}
// 获取权限访问列表
$accessList = self::getModuleAccessList($authId, $module);
return $accessList;
}
// 检查当前操作是否需要认证
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(CONTROLLER_NAME), $_module['no'])) || (! empty($_module['yes']) && in_array(strtoupper(CONTROLLER_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 (self::checkAccess()) {
// 检查认证识别号
if (! $_SESSION[C('USER_AUTH_KEY')]) {
if (C('GUEST_AUTH_ON')) {
// 开启游客授权访问
if (! isset($_SESSION['_ACCESS_LIST'])) // 保存游客权限
{
self::saveAccessList(C('GUEST_AUTH_ID'));
}
} else {
// 禁止游客访问跳转到认证网关
redirect(PHP_FILE . C('USER_AUTH_GATEWAY'));
}
}
}
return true;
}
// 权限认证的过滤器方法
static public function AccessDecision($appName = MODULE_NAME)
{
// 检查是否需要认证
if (self::checkAccess()) {
// 存在认证识别号,则进行进一步的访问决策
$accessGuid = md5($appName . CONTROLLER_NAME . ACTION_NAME);
if (empty($_SESSION[C('ADMIN_AUTH_KEY')])) {
if (C('USER_AUTH_TYPE') == 2) {
// 加强验证和即时验证模式 更加安全 后台权限修改可以即时生效
// 通过数据库进行访问检查
$accessList = self::getAccessList($_SESSION[C('USER_AUTH_KEY')]);
} else {
// 如果是管理员或者当前操作已经认证过,无需再次认证
if ($_SESSION[$accessGuid]) {
return true;
}
// 登录验证模式,比较登录后保存的权限访问列表
$accessList = $_SESSION['_ACCESS_LIST'];
}
// 判断是否为组件化模式,如果是,验证其全模块名
if (! isset($accessList[strtoupper($appName)][strtoupper(CONTROLLER_NAME)][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;
}
// 读取模块所属的记录访问权限
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;
}
}