mm_power 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/index.js +18 -1947
- package/lib/power.js +1969 -0
- package/lib/tools/index.js +16 -0
- package/lib/tools/power/index.js +62 -0
- package/package.json +13 -5
- package/tool/power/index.js +7 -0
- package/tool/power/tool.json +76 -0
package/lib/power.js
ADDED
|
@@ -0,0 +1,1969 @@
|
|
|
1
|
+
require('mm_helper');
|
|
2
|
+
const { kvStoreAdmin } = require('mm_kv_store');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 鉴权类
|
|
6
|
+
* @class
|
|
7
|
+
*/
|
|
8
|
+
class Power {
|
|
9
|
+
/**
|
|
10
|
+
* 创建鉴权实例
|
|
11
|
+
* @param {Object} config 配置
|
|
12
|
+
*/
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.config = {
|
|
15
|
+
// 用户ID字段名
|
|
16
|
+
user_id: 'user_id',
|
|
17
|
+
// 管理员级别字段名
|
|
18
|
+
gm: 'gm',
|
|
19
|
+
// VIP级别字段名
|
|
20
|
+
vip: 'vip',
|
|
21
|
+
// 商家级别字段名
|
|
22
|
+
mc: 'mc',
|
|
23
|
+
// 管理组权限字段名
|
|
24
|
+
admins: 'admins',
|
|
25
|
+
// 用户组权限字段名
|
|
26
|
+
groups: 'groups',
|
|
27
|
+
// 登录状态字段名
|
|
28
|
+
login: 'login',
|
|
29
|
+
// 权限生效开始时间字段名
|
|
30
|
+
time_start: 'time_start',
|
|
31
|
+
// 权限生效结束时间字段名
|
|
32
|
+
time_end: 'time_end'
|
|
33
|
+
};
|
|
34
|
+
this._stores = {}; // 数据键值存储实例缓存(路由/角色/用户组/管理组/缓存)
|
|
35
|
+
this._loader = null; // 异步加载器
|
|
36
|
+
this.setConfig(config || {});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 获取指定名称的键值存储实例(数据经 mm_kv_store 读写)
|
|
41
|
+
* @param {string} name 存储名称:routes / roles / groups / admins / cache
|
|
42
|
+
* @returns {Object} KvStore 键值存储实例
|
|
43
|
+
*/
|
|
44
|
+
_store(name) {
|
|
45
|
+
if (!this._stores[name]) {
|
|
46
|
+
const scope = `mm_power:${this.config.name || 'os'}:${name}`;
|
|
47
|
+
this._stores[name] = kvStoreAdmin(scope);
|
|
48
|
+
}
|
|
49
|
+
return this._stores[name];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 用给定对象整体替换存储内容
|
|
54
|
+
* @param {string} name 存储名称
|
|
55
|
+
* @param {Object} data 键值数据
|
|
56
|
+
* @returns {void}
|
|
57
|
+
*/
|
|
58
|
+
_setAll(name, data) {
|
|
59
|
+
const store = this._store(name);
|
|
60
|
+
store.clear();
|
|
61
|
+
for (const key in data) {
|
|
62
|
+
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
63
|
+
store.set(key, data[key]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 转换用户数据到内部标准格式
|
|
70
|
+
* @param {Object} userData 原始用户数据
|
|
71
|
+
* @returns {Object} 转换后的标准格式用户数据
|
|
72
|
+
*/
|
|
73
|
+
_transformUser(userData) {
|
|
74
|
+
if (!userData) return null;
|
|
75
|
+
|
|
76
|
+
// 如果已经是标准格式,直接返回
|
|
77
|
+
if (this._isStandardFormat(userData)) {
|
|
78
|
+
return userData;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const transformed = this._mapStandardFields(userData);
|
|
82
|
+
this._handleUndefined(userData, transformed);
|
|
83
|
+
this._copyOtherFields(userData, transformed);
|
|
84
|
+
|
|
85
|
+
return transformed;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
*
|
|
90
|
+
*/
|
|
91
|
+
_isStandardFormat(userData) {
|
|
92
|
+
return userData.user_id !== undefined &&
|
|
93
|
+
userData.admins !== undefined &&
|
|
94
|
+
userData.groups !== undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
*
|
|
99
|
+
*/
|
|
100
|
+
_mapStandardFields(userData) {
|
|
101
|
+
const transformed = {};
|
|
102
|
+
|
|
103
|
+
// 映射标准字段
|
|
104
|
+
transformed.user_id = userData[this.config.user_id];
|
|
105
|
+
transformed.gm = userData[this.config.gm];
|
|
106
|
+
transformed.vip = userData[this.config.vip];
|
|
107
|
+
transformed.mc = userData[this.config.mc];
|
|
108
|
+
transformed.admins = userData[this.config.admins];
|
|
109
|
+
transformed.groups = userData[this.config.groups];
|
|
110
|
+
transformed.login = userData[this.config.login];
|
|
111
|
+
transformed.time_start = userData[this.config.time_start];
|
|
112
|
+
transformed.time_end = userData[this.config.time_end];
|
|
113
|
+
|
|
114
|
+
return transformed;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
*
|
|
119
|
+
*/
|
|
120
|
+
_handleUndefined(userData, transformed) {
|
|
121
|
+
// 如果映射后的字段是undefined,但原始数据中存在同名字段,则使用原始数据
|
|
122
|
+
if (transformed.admins === undefined && userData.admins !== undefined) {
|
|
123
|
+
transformed.admins = userData.admins;
|
|
124
|
+
}
|
|
125
|
+
if (transformed.groups === undefined && userData.groups !== undefined) {
|
|
126
|
+
transformed.groups = userData.groups;
|
|
127
|
+
}
|
|
128
|
+
if (transformed.user_id === undefined && userData.user_id !== undefined) {
|
|
129
|
+
transformed.user_id = userData.user_id;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
*
|
|
135
|
+
*/
|
|
136
|
+
_copyOtherFields(userData, transformed) {
|
|
137
|
+
// 复制其他字段
|
|
138
|
+
for (const key in userData) {
|
|
139
|
+
if (!(key in transformed) && userData.hasOwnProperty(key)) {
|
|
140
|
+
transformed[key] = userData[key];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 设置异步配置加载器
|
|
148
|
+
* @param {Function} loader 异步加载器
|
|
149
|
+
*/
|
|
150
|
+
Power.prototype.setLoader = function (loader) {
|
|
151
|
+
if (typeof loader !== 'function') {
|
|
152
|
+
throw new TypeError('加载器必须是函数');
|
|
153
|
+
}
|
|
154
|
+
this._loader = loader;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 异步加载配置
|
|
159
|
+
* @param {string} type 配置类型
|
|
160
|
+
* @param {string} key 配置键
|
|
161
|
+
* @returns {Promise<Object>} 配置
|
|
162
|
+
*/
|
|
163
|
+
Power.prototype._loadConfig = async function (type, key) {
|
|
164
|
+
if (!this._loader) {
|
|
165
|
+
throw new Error('异步加载器未设置');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const cache_key = `${type}:${key}`;
|
|
169
|
+
const cached = this._store('cache').get(cache_key);
|
|
170
|
+
if (cached) {
|
|
171
|
+
return cached;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const config = await this._loader(type, key);
|
|
175
|
+
this._store('cache').set(cache_key, config);
|
|
176
|
+
return config;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 异步设置配置
|
|
181
|
+
* @param {Object} config 配置
|
|
182
|
+
* @returns {Promise<void>}
|
|
183
|
+
*/
|
|
184
|
+
Power.prototype.setConfigAsync = async function (config) {
|
|
185
|
+
if (!config) {
|
|
186
|
+
throw new TypeError('配置是必需的');
|
|
187
|
+
}
|
|
188
|
+
if (typeof config !== 'object') {
|
|
189
|
+
throw new TypeError('配置必须是对象');
|
|
190
|
+
}
|
|
191
|
+
Object.assign(this.config, config);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 异步设置路由权限配置
|
|
196
|
+
* @param {Object} routes 路由配置
|
|
197
|
+
* @returns {Promise<void>}
|
|
198
|
+
*/
|
|
199
|
+
Power.prototype.setRoutesAsync = async function (routes) {
|
|
200
|
+
if (!routes) {
|
|
201
|
+
throw new TypeError('路由是必需的');
|
|
202
|
+
}
|
|
203
|
+
if (typeof routes !== 'object') {
|
|
204
|
+
throw new TypeError('路由必须是对象');
|
|
205
|
+
}
|
|
206
|
+
this._setAll('routes', routes);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 异步设置角色权限配置
|
|
211
|
+
* @param {Object} roles 角色配置
|
|
212
|
+
* @returns {Promise<void>}
|
|
213
|
+
*/
|
|
214
|
+
Power.prototype.setRolesAsync = async function (roles) {
|
|
215
|
+
if (!roles) {
|
|
216
|
+
throw new TypeError('角色是必需的');
|
|
217
|
+
}
|
|
218
|
+
if (typeof roles !== 'object') {
|
|
219
|
+
throw new TypeError('角色必须是对象');
|
|
220
|
+
}
|
|
221
|
+
this._setAll('roles', roles);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 异步设置用户组配置
|
|
226
|
+
* @param {Object} groups 用户组配置
|
|
227
|
+
* @returns {Promise<void>}
|
|
228
|
+
*/
|
|
229
|
+
Power.prototype.setGroupsAsync = async function (groups) {
|
|
230
|
+
if (!groups) {
|
|
231
|
+
throw new TypeError('用户组是必需的');
|
|
232
|
+
}
|
|
233
|
+
if (typeof groups !== 'object') {
|
|
234
|
+
throw new TypeError('用户组必须是对象');
|
|
235
|
+
}
|
|
236
|
+
this._setAll('groups', groups);
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 异步设置管理组配置
|
|
241
|
+
* @param {Object} admins 管理组配置
|
|
242
|
+
* @returns {Promise<void>}
|
|
243
|
+
*/
|
|
244
|
+
Power.prototype.setAdminsAsync = async function (admins) {
|
|
245
|
+
if (!admins) {
|
|
246
|
+
throw new TypeError('管理组是必需的');
|
|
247
|
+
}
|
|
248
|
+
if (typeof admins !== 'object') {
|
|
249
|
+
throw new TypeError('管理组必须是对象');
|
|
250
|
+
}
|
|
251
|
+
this._setAll('admins', admins);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* 异步检查管理组权限
|
|
256
|
+
* @param {Object} user 用户
|
|
257
|
+
* @param {string} admin 管理组
|
|
258
|
+
* @returns {Promise<string>} 结果
|
|
259
|
+
*/
|
|
260
|
+
Power.prototype._checkAdminLevel = function (options, user) {
|
|
261
|
+
if (!options.gm || !user.gm) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (user.gm < options.gm) {
|
|
266
|
+
return `管理级别不足: ${user.gm} < ${options.gm}`;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return null;
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* 异步检查用户是否属于指定组
|
|
274
|
+
* @param {Object} user 用户
|
|
275
|
+
* @param {string} admin 管理组
|
|
276
|
+
* @returns {Promise<string>} 结果
|
|
277
|
+
*/
|
|
278
|
+
Power.prototype.checkAdminAsync = async function (user, admin) {
|
|
279
|
+
if (!user) {
|
|
280
|
+
throw new TypeError('用户是必需的');
|
|
281
|
+
}
|
|
282
|
+
if (!admin) {
|
|
283
|
+
throw new TypeError('管理组是必需的');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 如果user是字符串,则认为是用户ID,需要通过getUserAsync获取用户对象
|
|
287
|
+
const userObj = await this._getUserIfNeeded(user);
|
|
288
|
+
if (typeof user === 'string' && !userObj) {
|
|
289
|
+
return '用户不存在';
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 转换用户数据到内部标准格式
|
|
293
|
+
const std_user = this._transformUser(userObj);
|
|
294
|
+
|
|
295
|
+
// 异步加载管理组配置
|
|
296
|
+
const options = await this._loadConfig('admins', admin);
|
|
297
|
+
if (!options) {
|
|
298
|
+
return `管理组配置不存在: ${admin}`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// 检查各项权限
|
|
302
|
+
const checks = [
|
|
303
|
+
() => this._checkUserInAdmin(std_user, admin),
|
|
304
|
+
() => this._checkAdminTime(options, admin),
|
|
305
|
+
() => this._checkAdminIp(options, std_user),
|
|
306
|
+
() => this._checkAdminLevel(options, std_user)
|
|
307
|
+
];
|
|
308
|
+
|
|
309
|
+
for (const check of checks) {
|
|
310
|
+
const result = check();
|
|
311
|
+
if (result) {
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return '';
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
Power.prototype._getUserIfNeeded = async function (user) {
|
|
320
|
+
if (typeof user === 'string') {
|
|
321
|
+
return await this.getUserAsync(user);
|
|
322
|
+
}
|
|
323
|
+
return user;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
Power.prototype._checkUserInAdmin = function (user, admin) {
|
|
327
|
+
if (!user.admins || !user.admins.includes(admin)) {
|
|
328
|
+
return `用户不属于管理组: ${admin}`;
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* 异步检查管理组权限(支持多个管理组)
|
|
335
|
+
* @param {Object} user 用户
|
|
336
|
+
* @param {string|Array} admins 管理组
|
|
337
|
+
* @param {number} way 检查方式
|
|
338
|
+
* @returns {Promise<string>} 结果
|
|
339
|
+
*/
|
|
340
|
+
Power.prototype.checkAdminsAsync = async function (user, admins, way = 0) {
|
|
341
|
+
if (!user) {
|
|
342
|
+
throw new TypeError('用户是必需的');
|
|
343
|
+
}
|
|
344
|
+
if (!admins) {
|
|
345
|
+
throw new TypeError('管理组是必需的');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// 如果user是字符串,则认为是用户ID
|
|
349
|
+
const userObj = await this._getUserIfNeeded(user);
|
|
350
|
+
if (typeof user === 'string' && !userObj) {
|
|
351
|
+
return '用户不存在';
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const grps = Array.isArray(admins) ? admins : [admins];
|
|
355
|
+
|
|
356
|
+
switch (way) {
|
|
357
|
+
case 1:
|
|
358
|
+
return await this._checkAllAdminsAsync(userObj, grps);
|
|
359
|
+
case 2:
|
|
360
|
+
return await this._checkAnyAdminAsync(userObj, grps);
|
|
361
|
+
default:
|
|
362
|
+
return await this._checkFirstAdmin(userObj, grps);
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
Power.prototype._checkAllAdminsAsync = async function (userObj, grps) {
|
|
367
|
+
// 必须拥有所有管理组权限
|
|
368
|
+
for (const grp of grps) {
|
|
369
|
+
const res = await this.checkAdminAsync(userObj, grp);
|
|
370
|
+
if (res) {
|
|
371
|
+
return res;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return '';
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
Power.prototype._checkAnyAdminAsync = async function (userObj, grps) {
|
|
378
|
+
// 拥有任一管理组权限即可
|
|
379
|
+
for (const grp of grps) {
|
|
380
|
+
const res = await this.checkAdminAsync(userObj, grp);
|
|
381
|
+
if (!res) {
|
|
382
|
+
return '';
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return `缺少任一管理组权限: ${grps.join(', ')}`;
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
Power.prototype._checkFirstAdmin = async function (userObj, grps) {
|
|
389
|
+
// 默认检查第一个管理组
|
|
390
|
+
if (grps.length > 0) {
|
|
391
|
+
return await this.checkAdminAsync(userObj, grps[0]);
|
|
392
|
+
}
|
|
393
|
+
return '';
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* 设置配置
|
|
398
|
+
* @param {Object} config 配置
|
|
399
|
+
*/
|
|
400
|
+
Power.prototype.setConfig = function (config) {
|
|
401
|
+
if (!config) {
|
|
402
|
+
throw new TypeError('配置是必需的');
|
|
403
|
+
}
|
|
404
|
+
if (typeof config !== 'object') {
|
|
405
|
+
throw new TypeError('配置必须是对象');
|
|
406
|
+
}
|
|
407
|
+
Object.assign(this.config, config);
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* 设置路由权限配置
|
|
412
|
+
* @param {Object} routes 路由配置
|
|
413
|
+
*/
|
|
414
|
+
Power.prototype.setRoutes = function (routes) {
|
|
415
|
+
if (!routes) {
|
|
416
|
+
throw new TypeError('路由是必需的');
|
|
417
|
+
}
|
|
418
|
+
if (typeof routes !== 'object') {
|
|
419
|
+
throw new TypeError('路由必须是对象');
|
|
420
|
+
}
|
|
421
|
+
this._setAll('routes', routes);
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* 设置角色权限配置
|
|
426
|
+
* @param {Object} roles 角色配置
|
|
427
|
+
*/
|
|
428
|
+
Power.prototype.setRoles = function (roles) {
|
|
429
|
+
if (!roles) {
|
|
430
|
+
throw new TypeError('角色是必需的');
|
|
431
|
+
}
|
|
432
|
+
if (typeof roles !== 'object') {
|
|
433
|
+
throw new TypeError('角色必须是对象');
|
|
434
|
+
}
|
|
435
|
+
this._setAll('roles', roles);
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* 设置用户组配置
|
|
440
|
+
* @param {Object} groups 用户组配置
|
|
441
|
+
*/
|
|
442
|
+
Power.prototype.setGroups = function (groups) {
|
|
443
|
+
if (!groups) {
|
|
444
|
+
throw new TypeError('用户组是必需的');
|
|
445
|
+
}
|
|
446
|
+
if (typeof groups !== 'object') {
|
|
447
|
+
throw new TypeError('用户组必须是对象');
|
|
448
|
+
}
|
|
449
|
+
this._setAll('groups', groups);
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* 设置管理组配置
|
|
454
|
+
* @param {Object} admins 管理组配置
|
|
455
|
+
*/
|
|
456
|
+
Power.prototype.setAdmins = function (admins) {
|
|
457
|
+
if (!admins) {
|
|
458
|
+
throw new TypeError('管理组是必需的');
|
|
459
|
+
}
|
|
460
|
+
if (typeof admins !== 'object') {
|
|
461
|
+
throw new TypeError('管理组必须是对象');
|
|
462
|
+
}
|
|
463
|
+
this._setAll('admins', admins);
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* 检查管理组权限
|
|
468
|
+
* @param {Object} user 用户
|
|
469
|
+
* @param {string} admin 管理组
|
|
470
|
+
* @returns {string} 结果
|
|
471
|
+
*/
|
|
472
|
+
Power.prototype.checkAdmin = function (user, admin) {
|
|
473
|
+
if (!user) {
|
|
474
|
+
throw new TypeError('用户是必需的');
|
|
475
|
+
}
|
|
476
|
+
if (!admin) {
|
|
477
|
+
throw new TypeError('管理组是必需的');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// 转换用户数据到内部标准格式
|
|
481
|
+
const stdUser = this._transformUser(user);
|
|
482
|
+
|
|
483
|
+
// 检查用户是否属于该管理组
|
|
484
|
+
if (!stdUser.admins || !stdUser.admins.includes(admin)) {
|
|
485
|
+
return `用户不属于管理组: ${admin}`;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// 获取管理组配置
|
|
489
|
+
const options = this._store('admins').get(admin);
|
|
490
|
+
if (!options) {
|
|
491
|
+
return `管理组配置不存在: ${admin}`;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
return this._checkAdminDetails(options, stdUser, admin);
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* 检查管理组详细权限
|
|
499
|
+
* @param {Object} options 管理组配置
|
|
500
|
+
* @param {Object} stdUser 标准用户对象
|
|
501
|
+
* @param {string} admin 管理组
|
|
502
|
+
* @returns {string} 结果
|
|
503
|
+
*/
|
|
504
|
+
Power.prototype._checkAdminDetails = function (options, stdUser, admin) {
|
|
505
|
+
// 检查时间范围权限
|
|
506
|
+
const time_result = this._checkAdminTime(options, admin);
|
|
507
|
+
if (time_result) {
|
|
508
|
+
return time_result;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// 检查IP白名单
|
|
512
|
+
const ip_result = this._checkAdminIp(options, stdUser);
|
|
513
|
+
if (ip_result) {
|
|
514
|
+
return ip_result;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// 检查管理级别
|
|
518
|
+
const level_result = this._checkAdminLevel(options, stdUser);
|
|
519
|
+
if (level_result) {
|
|
520
|
+
return level_result;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return '';
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* 检查管理组时间范围权限
|
|
528
|
+
* @param {Object} options 管理组配置
|
|
529
|
+
* @param {string} admin 管理组
|
|
530
|
+
* @returns {string} 结果
|
|
531
|
+
*/
|
|
532
|
+
Power.prototype._checkAdminTime = function (options, admin) {
|
|
533
|
+
if (!options.time_start || !options.time_end) {
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
const now = new Date();
|
|
538
|
+
const start = new Date(options.time_start);
|
|
539
|
+
const end = new Date(options.time_end);
|
|
540
|
+
|
|
541
|
+
if (now < start || now > end) {
|
|
542
|
+
return `管理组时间范围权限不足: ${admin}`;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return null;
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* 检查管理组IP白名单权限
|
|
550
|
+
* @param {Object} options 管理组配置
|
|
551
|
+
* @param {Object} user 用户
|
|
552
|
+
* @returns {string} 结果
|
|
553
|
+
*/
|
|
554
|
+
Power.prototype._checkAdminIp = function (options, user) {
|
|
555
|
+
if (!options.ip_whitelist || !user.ip) {
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (!options.ip_whitelist.includes(user.ip)) {
|
|
560
|
+
return `IP不在管理组白名单内: ${user.ip}`;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
return null;
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* 检查管理级别权限
|
|
568
|
+
* @param {Object} options 管理组配置
|
|
569
|
+
* @param {Object} user 用户
|
|
570
|
+
* @returns {string} 结果
|
|
571
|
+
*/
|
|
572
|
+
Power.prototype._checkAdminLevel = function (options, user) {
|
|
573
|
+
if (!options.gm || !user.gm) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (user.gm < options.gm) {
|
|
578
|
+
return `管理级别不足: ${user.gm} < ${options.gm}`;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return null;
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* 检查管理组权限(支持多个管理组)
|
|
586
|
+
* @param {Object} user 用户
|
|
587
|
+
* @param {string|Array} admins 管理组
|
|
588
|
+
* @param {number} way 检查方式
|
|
589
|
+
* @returns {string} 结果
|
|
590
|
+
*/
|
|
591
|
+
Power.prototype.checkAdmins = function (user, admins, way = 0) {
|
|
592
|
+
if (!user) {
|
|
593
|
+
throw new TypeError('用户是必需的');
|
|
594
|
+
}
|
|
595
|
+
if (!admins) {
|
|
596
|
+
throw new TypeError('管理组是必需的');
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// 转换用户数据到内部标准格式
|
|
600
|
+
const std_user = this._transformUser(user);
|
|
601
|
+
|
|
602
|
+
const grps = Array.isArray(admins) ? admins : [admins];
|
|
603
|
+
|
|
604
|
+
if (way === 1) {
|
|
605
|
+
return this._checkAllAdmins(std_user, grps);
|
|
606
|
+
} else if (way === 2) {
|
|
607
|
+
return this._checkAnyAdmin(std_user, grps);
|
|
608
|
+
} else {
|
|
609
|
+
return this._checkFirstAdmin(std_user, grps);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* 检查所有管理组权限
|
|
615
|
+
* @param {Object} user 用户
|
|
616
|
+
* @param {Array} grps 管理组列表
|
|
617
|
+
* @returns {string} 结果
|
|
618
|
+
*/
|
|
619
|
+
Power.prototype._checkAllAdmins = function (user, grps) {
|
|
620
|
+
for (const grp of grps) {
|
|
621
|
+
const res = this.checkAdmin(user, grp);
|
|
622
|
+
if (res) {
|
|
623
|
+
return res;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return '';
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* 检查任一管理组权限
|
|
631
|
+
* @param {Object} user 用户
|
|
632
|
+
* @param {Array} grps 管理组列表
|
|
633
|
+
* @returns {string} 结果
|
|
634
|
+
*/
|
|
635
|
+
Power.prototype._checkAnyAdmin = function (user, grps) {
|
|
636
|
+
let has_perm = false;
|
|
637
|
+
for (const grp of grps) {
|
|
638
|
+
const res = this.checkAdmin(user, grp);
|
|
639
|
+
if (!res) {
|
|
640
|
+
has_perm = true;
|
|
641
|
+
break;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (!has_perm) {
|
|
645
|
+
return `缺少任一管理组权限: ${grps.join(', ')}`;
|
|
646
|
+
}
|
|
647
|
+
return '';
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* 检查第一个管理组权限
|
|
652
|
+
* @param {Object} user 用户
|
|
653
|
+
* @param {Array} grps 管理组列表
|
|
654
|
+
* @returns {string} 结果
|
|
655
|
+
*/
|
|
656
|
+
Power.prototype._checkFirstAdmin = function (user, grps) {
|
|
657
|
+
if (grps.length > 0) {
|
|
658
|
+
return this.checkAdmin(user, grps[0]);
|
|
659
|
+
}
|
|
660
|
+
return '';
|
|
661
|
+
};
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* 检查字段权限
|
|
665
|
+
* @param {Object} user 用户
|
|
666
|
+
* @param {Object} power 权限
|
|
667
|
+
* @param {Function} func 函数
|
|
668
|
+
* @param {number} way 方式
|
|
669
|
+
* @returns {string} 结果
|
|
670
|
+
*/
|
|
671
|
+
Power.prototype.checkField = function (
|
|
672
|
+
user,
|
|
673
|
+
power = {
|
|
674
|
+
vip: 0,
|
|
675
|
+
gm: 0,
|
|
676
|
+
mc: 0
|
|
677
|
+
},
|
|
678
|
+
func,
|
|
679
|
+
way = 0
|
|
680
|
+
) {
|
|
681
|
+
if (!user) {
|
|
682
|
+
throw new TypeError('用户是必需的');
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// 转换用户数据到内部标准格式
|
|
686
|
+
const std_user = this._transformUser(user);
|
|
687
|
+
|
|
688
|
+
this._initUserFields(std_user);
|
|
689
|
+
|
|
690
|
+
if (way === 1) {
|
|
691
|
+
return this._checkAllFields(std_user, power);
|
|
692
|
+
} else if (way === 2) {
|
|
693
|
+
return this._checkAnyFields(std_user, power);
|
|
694
|
+
} else {
|
|
695
|
+
return this._checkDefaultFields(std_user, power);
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* 初始化用户字段
|
|
701
|
+
* @param {Object} user 用户
|
|
702
|
+
*/
|
|
703
|
+
Power.prototype._initUserFields = function (user) {
|
|
704
|
+
if (!user.vip) {
|
|
705
|
+
user.vip = 0;
|
|
706
|
+
}
|
|
707
|
+
if (!user.gm) {
|
|
708
|
+
user.gm = 0;
|
|
709
|
+
}
|
|
710
|
+
if (!user.mc) {
|
|
711
|
+
user.mc = 0;
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* 检查所有字段权限
|
|
717
|
+
* @param {Object} user 用户
|
|
718
|
+
* @param {Object} power 权限
|
|
719
|
+
* @returns {string} 结果
|
|
720
|
+
*/
|
|
721
|
+
Power.prototype._checkAllFields = function (user, power) {
|
|
722
|
+
if (user.gm < power.gm) {
|
|
723
|
+
return 'gm等级不足';
|
|
724
|
+
}
|
|
725
|
+
if (user.mc < power.mc) {
|
|
726
|
+
return 'mc等级不足';
|
|
727
|
+
}
|
|
728
|
+
if (user.vip < power.vip) {
|
|
729
|
+
return 'vip等级不足';
|
|
730
|
+
}
|
|
731
|
+
return '';
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* 检查任一字段权限
|
|
736
|
+
* @param {Object} user 用户
|
|
737
|
+
* @param {Object} power 权限
|
|
738
|
+
* @returns {string} 结果
|
|
739
|
+
*/
|
|
740
|
+
Power.prototype._checkAnyFields = function (user, power) {
|
|
741
|
+
if (user.vip < power.vip && user.gm < power.gm && user.mc < power.mc) {
|
|
742
|
+
return 'vip等级、gm等级、mc等级不足';
|
|
743
|
+
}
|
|
744
|
+
return '';
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* 检查默认字段权限
|
|
749
|
+
* @param {Object} user 用户
|
|
750
|
+
* @param {Object} power 权限
|
|
751
|
+
* @returns {string} 结果
|
|
752
|
+
*/
|
|
753
|
+
Power.prototype._checkDefaultFields = function (user, power) {
|
|
754
|
+
if (user.gm < power.gm) {
|
|
755
|
+
if (user.vip < power.vip && user.mc < power.mc) {
|
|
756
|
+
return 'vip等级、mc等级不足';
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return '';
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* 获取用户
|
|
764
|
+
* @param {string} user_id 用户ID
|
|
765
|
+
* @returns {Object} 用户
|
|
766
|
+
*/
|
|
767
|
+
Power.prototype.getUser = async function (user_id) {
|
|
768
|
+
return {
|
|
769
|
+
vip: 2,
|
|
770
|
+
gm: 5,
|
|
771
|
+
mc: 3,
|
|
772
|
+
admin: '',
|
|
773
|
+
group: 'vip'
|
|
774
|
+
};
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* 检查权限
|
|
779
|
+
* @param {string} user_id 用户ID
|
|
780
|
+
* @param {Function} func 函数
|
|
781
|
+
* @param {number} way 方式
|
|
782
|
+
* @returns {string} 结果
|
|
783
|
+
*/
|
|
784
|
+
Power.prototype.check = async function (
|
|
785
|
+
user_id,
|
|
786
|
+
power = {},
|
|
787
|
+
func = null,
|
|
788
|
+
way = 0
|
|
789
|
+
) {
|
|
790
|
+
const user = await this.getUser(user_id);
|
|
791
|
+
if (!user) {
|
|
792
|
+
return '用户不存在';
|
|
793
|
+
}
|
|
794
|
+
const result = this.checkField(user, power, func, way);
|
|
795
|
+
if (result) {
|
|
796
|
+
return result;
|
|
797
|
+
}
|
|
798
|
+
const result2 = this.checkPath(user, power, func, way);
|
|
799
|
+
if (result2) {
|
|
800
|
+
return result2;
|
|
801
|
+
}
|
|
802
|
+
const result3 = this.checkMethod(user, power, func, way);
|
|
803
|
+
if (result3) {
|
|
804
|
+
return result3;
|
|
805
|
+
}
|
|
806
|
+
return '';
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* 检查路径权限
|
|
811
|
+
* @param {Object} user 用户
|
|
812
|
+
* @param {Object} power 权限
|
|
813
|
+
* @param {Function} func 函数
|
|
814
|
+
* @param {number} way 方式
|
|
815
|
+
* @returns {string} 结果
|
|
816
|
+
*/
|
|
817
|
+
Power.prototype.checkPath = function (user, power = {}, func = null, way = 0) {
|
|
818
|
+
if (!user) {
|
|
819
|
+
throw new TypeError('用户是必需的');
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// 转换用户数据到内部标准格式
|
|
823
|
+
const std_user = this._transformUser(user);
|
|
824
|
+
|
|
825
|
+
if (power.path) {
|
|
826
|
+
const user_paths = std_user.paths || [];
|
|
827
|
+
const required_paths = Array.isArray(power.path)
|
|
828
|
+
? power.path
|
|
829
|
+
: [power.path];
|
|
830
|
+
|
|
831
|
+
if (way === 1) {
|
|
832
|
+
return this._checkAllPaths(user_paths, required_paths);
|
|
833
|
+
} else if (way === 2) {
|
|
834
|
+
return this._checkAnyPath(user_paths, required_paths);
|
|
835
|
+
} else {
|
|
836
|
+
return this._checkFirstPath(user_paths, required_paths);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (func) {
|
|
841
|
+
return func(std_user, power, 'checkPath');
|
|
842
|
+
}
|
|
843
|
+
return '';
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* 检查所有路径权限
|
|
848
|
+
* @param {Array} user_paths 用户路径列表
|
|
849
|
+
* @param {Array} required_paths 所需路径列表
|
|
850
|
+
* @returns {string} 结果
|
|
851
|
+
*/
|
|
852
|
+
Power.prototype._checkAllPaths = function (user_paths, required_paths) {
|
|
853
|
+
for (const path of required_paths) {
|
|
854
|
+
if (!user_paths.includes(path)) {
|
|
855
|
+
return `缺少路径权限: ${path}`;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
return '';
|
|
859
|
+
};
|
|
860
|
+
|
|
861
|
+
/**
|
|
862
|
+
* 检查任一路径权限
|
|
863
|
+
* @param {Array} user_paths 用户路径列表
|
|
864
|
+
* @param {Array} required_paths 所需路径列表
|
|
865
|
+
* @returns {string} 结果
|
|
866
|
+
*/
|
|
867
|
+
Power.prototype._checkAnyPath = function (user_paths, required_paths) {
|
|
868
|
+
let has_access = false;
|
|
869
|
+
for (const path of required_paths) {
|
|
870
|
+
if (user_paths.includes(path)) {
|
|
871
|
+
has_access = true;
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
if (!has_access) {
|
|
876
|
+
return '无任何路径权限';
|
|
877
|
+
}
|
|
878
|
+
return '';
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
/**
|
|
882
|
+
* 检查第一个路径权限
|
|
883
|
+
* @param {Array} user_paths 用户路径列表
|
|
884
|
+
* @param {Array} required_paths 所需路径列表
|
|
885
|
+
* @returns {string} 结果
|
|
886
|
+
*/
|
|
887
|
+
Power.prototype._checkFirstPath = function (user_paths, required_paths) {
|
|
888
|
+
if (required_paths.length > 0 && !user_paths.includes(required_paths[0])) {
|
|
889
|
+
return `缺少路径权限: ${required_paths[0]}`;
|
|
890
|
+
}
|
|
891
|
+
return '';
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* 检查方法权限
|
|
896
|
+
* @param {Object} user 用户
|
|
897
|
+
* @param {Object} power 权限
|
|
898
|
+
* @param {Function} func 函数
|
|
899
|
+
* @param {number} way 方式
|
|
900
|
+
* @returns {string} 结果
|
|
901
|
+
*/
|
|
902
|
+
Power.prototype.checkMethod = function (
|
|
903
|
+
user,
|
|
904
|
+
power = {},
|
|
905
|
+
func = null,
|
|
906
|
+
way = 0
|
|
907
|
+
) {
|
|
908
|
+
if (!user) {
|
|
909
|
+
throw new TypeError('用户是必需的');
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
// 转换用户数据到内部标准格式
|
|
913
|
+
const std_user = this._transformUser(user);
|
|
914
|
+
|
|
915
|
+
if (power.method) {
|
|
916
|
+
const method_result = this._checkMethodWay(std_user, power, way);
|
|
917
|
+
if (method_result) {
|
|
918
|
+
return method_result;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
if (func) {
|
|
923
|
+
return func(std_user, power, 'checkMethod');
|
|
924
|
+
}
|
|
925
|
+
return '';
|
|
926
|
+
};
|
|
927
|
+
|
|
928
|
+
/**
|
|
929
|
+
* 检查方法权限方式
|
|
930
|
+
* @param {Object} user 用户
|
|
931
|
+
* @param {Object} power 权限
|
|
932
|
+
* @param {number} way 方式
|
|
933
|
+
* @returns {string} 结果
|
|
934
|
+
*/
|
|
935
|
+
Power.prototype._checkMethodWay = function (user, power, way) {
|
|
936
|
+
const user_methods = user.methods || [];
|
|
937
|
+
const required_methods = Array.isArray(power.method)
|
|
938
|
+
? power.method
|
|
939
|
+
: [power.method];
|
|
940
|
+
|
|
941
|
+
if (way === 1) {
|
|
942
|
+
return this._checkAllMethods(user_methods, required_methods);
|
|
943
|
+
} else if (way === 2) {
|
|
944
|
+
return this._checkAnyMethod(user_methods, required_methods);
|
|
945
|
+
} else {
|
|
946
|
+
return this._checkFirstMethod(user_methods, required_methods);
|
|
947
|
+
}
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
* 检查所有方法权限
|
|
952
|
+
* @param {Array} user_methods 用户方法
|
|
953
|
+
* @param {Array} required_methods 要求方法
|
|
954
|
+
* @returns {string} 结果
|
|
955
|
+
*/
|
|
956
|
+
Power.prototype._checkAllMethods = function (user_methods, required_methods) {
|
|
957
|
+
for (const method of required_methods) {
|
|
958
|
+
if (!user_methods.includes(method.toUpperCase())) {
|
|
959
|
+
return `缺少方法权限: ${method}`;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
return null;
|
|
963
|
+
};
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* 检查任一方法权限
|
|
967
|
+
* @param {Array} user_methods 用户方法
|
|
968
|
+
* @param {Array} required_methods 要求方法
|
|
969
|
+
* @returns {string} 结果
|
|
970
|
+
*/
|
|
971
|
+
Power.prototype._checkAnyMethod = function (user_methods, required_methods) {
|
|
972
|
+
let has_access = false;
|
|
973
|
+
for (const method of required_methods) {
|
|
974
|
+
if (user_methods.includes(method.toUpperCase())) {
|
|
975
|
+
has_access = true;
|
|
976
|
+
break;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
if (!has_access) {
|
|
980
|
+
return '无任何方法权限';
|
|
981
|
+
}
|
|
982
|
+
return null;
|
|
983
|
+
};
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* 检查第一个方法权限
|
|
987
|
+
* @param {Array} user_methods 用户方法
|
|
988
|
+
* @param {Array} required_methods 要求方法
|
|
989
|
+
* @returns {string} 结果
|
|
990
|
+
*/
|
|
991
|
+
Power.prototype._checkFirstMethod = function (user_methods, required_methods) {
|
|
992
|
+
if (
|
|
993
|
+
required_methods.length > 0 &&
|
|
994
|
+
!user_methods.includes(required_methods[0].toUpperCase())
|
|
995
|
+
) {
|
|
996
|
+
return `缺少方法权限: ${required_methods[0]}`;
|
|
997
|
+
}
|
|
998
|
+
return null;
|
|
999
|
+
};
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* 检查角色权限
|
|
1003
|
+
* @param {Object} user 用户
|
|
1004
|
+
* @param {string} role 角色
|
|
1005
|
+
* @returns {string} 结果
|
|
1006
|
+
*/
|
|
1007
|
+
Power.prototype.checkRole = function (user, role) {
|
|
1008
|
+
if (!user) {
|
|
1009
|
+
throw new TypeError('用户是必需的');
|
|
1010
|
+
}
|
|
1011
|
+
if (!role) {
|
|
1012
|
+
throw new TypeError('角色是必需的');
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
// 转换用户数据到内部标准格式
|
|
1016
|
+
const std_user = this._transformUser(user);
|
|
1017
|
+
|
|
1018
|
+
const user_roles = std_user.roles || [];
|
|
1019
|
+
if (!user_roles.includes(role)) {
|
|
1020
|
+
return `缺少角色权限: ${role}`;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// 检查角色层级
|
|
1024
|
+
const role_cfg = this._store('roles').get(role);
|
|
1025
|
+
if (role_cfg) {
|
|
1026
|
+
const required_level = role_cfg.level || 0;
|
|
1027
|
+
const user_level = std_user.level || 0;
|
|
1028
|
+
if (user_level < required_level) {
|
|
1029
|
+
return `角色等级不足: ${role}`;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
return '';
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* 检查用户组权限
|
|
1038
|
+
* @param {Object} user 用户
|
|
1039
|
+
* @param {string} group 用户组
|
|
1040
|
+
* @returns {string} 结果
|
|
1041
|
+
*/
|
|
1042
|
+
Power.prototype.checkGroup = function (user, group) {
|
|
1043
|
+
if (!user) {
|
|
1044
|
+
throw new TypeError('用户是必需的');
|
|
1045
|
+
}
|
|
1046
|
+
if (!group) {
|
|
1047
|
+
throw new TypeError('用户组是必需的');
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
// 转换用户数据到内部标准格式
|
|
1051
|
+
const std_user = this._transformUser(user);
|
|
1052
|
+
|
|
1053
|
+
const user_groups = std_user.groups || [];
|
|
1054
|
+
if (!user_groups.includes(group)) {
|
|
1055
|
+
return `缺少用户组权限: ${group}`;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
// 检查用户组权限
|
|
1059
|
+
const options = this._store('groups').get(group);
|
|
1060
|
+
if (options) {
|
|
1061
|
+
const time_result = this._checkGroupTime(options, group);
|
|
1062
|
+
if (time_result) {
|
|
1063
|
+
return time_result;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
const ip_result = this._checkGroupIp(options, std_user);
|
|
1067
|
+
if (ip_result) {
|
|
1068
|
+
return ip_result;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
return '';
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* 检查用户组时间范围权限
|
|
1077
|
+
* @param {Object} options 用户组配置
|
|
1078
|
+
* @param {string} group 用户组
|
|
1079
|
+
* @returns {string} 结果
|
|
1080
|
+
*/
|
|
1081
|
+
Power.prototype._checkGroupTime = function (options, group) {
|
|
1082
|
+
if (!options.time_start || !options.time_end) {
|
|
1083
|
+
return null;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
const now = new Date();
|
|
1087
|
+
const start = new Date(options.time_start);
|
|
1088
|
+
const end = new Date(options.time_end);
|
|
1089
|
+
if (now < start || now > end) {
|
|
1090
|
+
return `用户组时间范围限制: ${group}`;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
return null;
|
|
1094
|
+
};
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* 检查用户组IP白名单权限
|
|
1098
|
+
* @param {Object} options 用户组配置
|
|
1099
|
+
* @param {Object} user 用户
|
|
1100
|
+
* @returns {string} 结果
|
|
1101
|
+
*/
|
|
1102
|
+
Power.prototype._checkGroupIp = function (options, user) {
|
|
1103
|
+
if (!options.ip_whitelist || !user.ip) {
|
|
1104
|
+
return null;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
const allowed_ips = options.ip_whitelist;
|
|
1108
|
+
if (!allowed_ips.includes(user.ip)) {
|
|
1109
|
+
return `IP不在白名单内: ${user.ip}`;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
return null;
|
|
1113
|
+
};
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* 检查路由权限
|
|
1117
|
+
* @param {Object} user 用户
|
|
1118
|
+
* @param {string} path 路径
|
|
1119
|
+
* @param {string} method 方法
|
|
1120
|
+
* @returns {string} 结果
|
|
1121
|
+
*/
|
|
1122
|
+
Power.prototype._findRouteConfig = function (path) {
|
|
1123
|
+
const routes = this._store('routes').list();
|
|
1124
|
+
for (const route_path in routes) {
|
|
1125
|
+
if (this._matchRoute(path, route_path)) {
|
|
1126
|
+
return routes[route_path];
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return null;
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
Power.prototype._checkMethod = function (route_cfg, method) {
|
|
1133
|
+
const method_cfg = route_cfg.methods || {};
|
|
1134
|
+
const allowed_methods = method_cfg[method.toUpperCase()] || method_cfg['*'];
|
|
1135
|
+
|
|
1136
|
+
if (!allowed_methods) {
|
|
1137
|
+
return `方法不允许: ${method}`;
|
|
1138
|
+
}
|
|
1139
|
+
return allowed_methods;
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
Power.prototype._checkRole = function (user, allowed_methods) {
|
|
1143
|
+
if (!allowed_methods.roles) {
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
const req_roles = Array.isArray(allowed_methods.roles)
|
|
1148
|
+
? allowed_methods.roles
|
|
1149
|
+
: [allowed_methods.roles];
|
|
1150
|
+
|
|
1151
|
+
for (const role of req_roles) {
|
|
1152
|
+
if (this.checkRole(user, role) === '') {
|
|
1153
|
+
return null;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
return `缺少所需角色权限: ${req_roles.join(', ')}`;
|
|
1158
|
+
};
|
|
1159
|
+
|
|
1160
|
+
Power.prototype._checkGroup = function (user, allowed_methods) {
|
|
1161
|
+
if (!allowed_methods.groups) {
|
|
1162
|
+
return null;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
const req_groups = Array.isArray(allowed_methods.groups)
|
|
1166
|
+
? allowed_methods.groups
|
|
1167
|
+
: [allowed_methods.groups];
|
|
1168
|
+
|
|
1169
|
+
for (const group of req_groups) {
|
|
1170
|
+
if (this.checkGroup(user, group) === '') {
|
|
1171
|
+
return null;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
return `缺少所需用户组权限: ${req_groups.join(', ')}`;
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
Power.prototype._checkAdminPerm = function (user, allowed_methods) {
|
|
1179
|
+
if (!allowed_methods.admins) {
|
|
1180
|
+
return null;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const req_admins = Array.isArray(allowed_methods.admins)
|
|
1184
|
+
? allowed_methods.admins
|
|
1185
|
+
: [allowed_methods.admins];
|
|
1186
|
+
|
|
1187
|
+
for (const admin of req_admins) {
|
|
1188
|
+
if (this.checkAdmin(user, admin) === '') {
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
return `缺少所需管理组权限: ${req_admins.join(', ')}`;
|
|
1194
|
+
};
|
|
1195
|
+
|
|
1196
|
+
Power.prototype._checkDataScope = function (user, allowed_methods) {
|
|
1197
|
+
if (!allowed_methods.scope || !user.scope) {
|
|
1198
|
+
return null;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
const user_scope = user.scope;
|
|
1202
|
+
const req_scope = allowed_methods.scope;
|
|
1203
|
+
|
|
1204
|
+
if (!this._checkDataScope(user_scope, req_scope)) {
|
|
1205
|
+
return '数据范围权限不足';
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
return null;
|
|
1209
|
+
};
|
|
1210
|
+
|
|
1211
|
+
Power.prototype.checkRoute = function (user, path, method = 'GET') {
|
|
1212
|
+
if (!user) {
|
|
1213
|
+
throw new TypeError('用户是必需的');
|
|
1214
|
+
}
|
|
1215
|
+
if (!path) {
|
|
1216
|
+
throw new TypeError('路径是必需的');
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// 转换用户数据到内部标准格式
|
|
1220
|
+
const std_user = this._transformUser(user);
|
|
1221
|
+
|
|
1222
|
+
// 查找路由配置
|
|
1223
|
+
const route_cfg = this._findRouteConfig(path);
|
|
1224
|
+
if (!route_cfg) {
|
|
1225
|
+
return ''; // 无路由配置,默认允许
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// 检查方法权限
|
|
1229
|
+
const method_result = this._checkMethod(route_cfg, method);
|
|
1230
|
+
if (typeof method_result === 'string') {
|
|
1231
|
+
return method_result;
|
|
1232
|
+
}
|
|
1233
|
+
const allowed_methods = method_result;
|
|
1234
|
+
|
|
1235
|
+
// 检查所有权限类型
|
|
1236
|
+
const result = this._checkAllRoutePerms(std_user, allowed_methods);
|
|
1237
|
+
if (result) {
|
|
1238
|
+
return result;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
return '';
|
|
1242
|
+
};
|
|
1243
|
+
|
|
1244
|
+
/**
|
|
1245
|
+
* 检查所有路由权限
|
|
1246
|
+
* @param {Object} user 用户
|
|
1247
|
+
* @param {Object} allowed_methods 允许的方法
|
|
1248
|
+
* @returns {string} 结果
|
|
1249
|
+
*/
|
|
1250
|
+
Power.prototype._checkAllRoutePerms = function (user, allowed_methods) {
|
|
1251
|
+
const checks = [
|
|
1252
|
+
() => this._checkRole(user, allowed_methods),
|
|
1253
|
+
() => this._checkGroup(user, allowed_methods),
|
|
1254
|
+
() => this._checkAdminPerm(user, allowed_methods),
|
|
1255
|
+
() => this._checkDataScope(user, allowed_methods)
|
|
1256
|
+
];
|
|
1257
|
+
|
|
1258
|
+
for (const check of checks) {
|
|
1259
|
+
const result = check();
|
|
1260
|
+
if (result) {
|
|
1261
|
+
return result;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
return null;
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
/**
|
|
1268
|
+
* 异步检查角色权限
|
|
1269
|
+
* @param {Object} user 用户
|
|
1270
|
+
* @param {string} role 角色
|
|
1271
|
+
* @returns {Promise<string>} 结果
|
|
1272
|
+
*/
|
|
1273
|
+
Power.prototype.checkRoleAsync = async function (user, role) {
|
|
1274
|
+
if (!user) {
|
|
1275
|
+
throw new TypeError('用户是必需的');
|
|
1276
|
+
}
|
|
1277
|
+
if (!role) {
|
|
1278
|
+
throw new TypeError('角色是必需的');
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// 如果user是字符串,则认为是用户ID,需要通过getUserAsync获取用户对象
|
|
1282
|
+
let userObj = user;
|
|
1283
|
+
if (typeof user === 'string') {
|
|
1284
|
+
userObj = await this.getUserAsync(user);
|
|
1285
|
+
if (!userObj) {
|
|
1286
|
+
return '用户不存在';
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
// 转换用户数据到内部标准格式
|
|
1291
|
+
const std_user = this._transformUser(userObj);
|
|
1292
|
+
|
|
1293
|
+
const user_roles = std_user.roles || [];
|
|
1294
|
+
if (!user_roles.includes(role)) {
|
|
1295
|
+
return `缺少角色权限: ${role}`;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// 异步加载角色配置
|
|
1299
|
+
const role_config = await this._loadConfig('roles', role);
|
|
1300
|
+
if (role_config) {
|
|
1301
|
+
const required_level = role_config.level || 0;
|
|
1302
|
+
const user_level = std_user.level || 0;
|
|
1303
|
+
if (user_level < required_level) {
|
|
1304
|
+
return `角色等级不足: ${role}`;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
return '';
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* 异步检查用户组权限
|
|
1313
|
+
* @param {Object} user 用户
|
|
1314
|
+
* @param {string} group 用户组
|
|
1315
|
+
* @returns {Promise<string>} 结果
|
|
1316
|
+
*/
|
|
1317
|
+
Power.prototype.checkGroupAsync = async function (user, group) {
|
|
1318
|
+
if (!user) {
|
|
1319
|
+
throw new TypeError('用户是必需的');
|
|
1320
|
+
}
|
|
1321
|
+
if (!group) {
|
|
1322
|
+
throw new TypeError('用户组是必需的');
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
// 如果user是字符串,则认为是用户ID,需要通过getUserAsync获取用户对象
|
|
1326
|
+
let userObj = user;
|
|
1327
|
+
if (typeof user === 'string') {
|
|
1328
|
+
userObj = await this.getUserAsync(user);
|
|
1329
|
+
if (!userObj) {
|
|
1330
|
+
return '用户不存在';
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// 转换用户数据到内部标准格式
|
|
1335
|
+
const std_user = this._transformUser(userObj);
|
|
1336
|
+
|
|
1337
|
+
const user_groups = std_user.groups || [];
|
|
1338
|
+
if (!user_groups.includes(group)) {
|
|
1339
|
+
return `缺少用户组权限: ${group}`;
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// 异步加载用户组配置
|
|
1343
|
+
const options = await this._loadConfig('groups', group);
|
|
1344
|
+
if (options) {
|
|
1345
|
+
return await this._checkGrpDtlAsync(options, std_user, group);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
return '';
|
|
1349
|
+
};
|
|
1350
|
+
|
|
1351
|
+
/**
|
|
1352
|
+
* 异步检查用户组详细权限
|
|
1353
|
+
* @param {Object} options 用户组配置
|
|
1354
|
+
* @param {Object} std_user 标准用户对象
|
|
1355
|
+
* @param {string} group 用户组
|
|
1356
|
+
* @returns {Promise<string>} 结果
|
|
1357
|
+
*/
|
|
1358
|
+
Power.prototype._checkGrpDtlAsync = async function (options, std_user, group) {
|
|
1359
|
+
const time_result = await this._checkGroupTimeAsync(options, group);
|
|
1360
|
+
if (time_result) {
|
|
1361
|
+
return time_result;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
const ip_result = this._checkGroupIpAsync(options, std_user);
|
|
1365
|
+
if (ip_result) {
|
|
1366
|
+
return ip_result;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
return '';
|
|
1370
|
+
};
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* 异步检查用户组时间范围权限
|
|
1374
|
+
* @param {Object} options 用户组配置
|
|
1375
|
+
* @param {string} group 用户组
|
|
1376
|
+
* @returns {Promise<string>} 结果
|
|
1377
|
+
*/
|
|
1378
|
+
Power.prototype._checkGroupTimeAsync = async function (options, group) {
|
|
1379
|
+
// 检查是否存在时间配置
|
|
1380
|
+
if (!options.time_start && !options.time_end) {
|
|
1381
|
+
return '';
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
const now = new Date();
|
|
1385
|
+
const start = options.time_start ? new Date(options.time_start) : null;
|
|
1386
|
+
const end = options.time_end ? new Date(options.time_end) : null;
|
|
1387
|
+
|
|
1388
|
+
// 检查开始时间
|
|
1389
|
+
if (start && now < start) {
|
|
1390
|
+
return `用户组时间范围限制: ${group}`;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
// 检查结束时间
|
|
1394
|
+
if (end && now > end) {
|
|
1395
|
+
return `用户组时间范围限制: ${group}`;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
return '';
|
|
1399
|
+
};
|
|
1400
|
+
|
|
1401
|
+
/**
|
|
1402
|
+
* 异步检查用户组IP白名单权限
|
|
1403
|
+
* @param {Object} options 用户组配置
|
|
1404
|
+
* @param {Object} user 用户
|
|
1405
|
+
* @returns {Promise<string|null>} 结果
|
|
1406
|
+
*/
|
|
1407
|
+
Power.prototype._checkGroupIpAsync = async function (options, user) {
|
|
1408
|
+
if (!options.ip_whitelist || !user.ip) {
|
|
1409
|
+
return '';
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
const allowed_ips = options.ip_whitelist;
|
|
1413
|
+
if (!allowed_ips.includes(user.ip)) {
|
|
1414
|
+
return `IP不在白名单内: ${user.ip}`;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
return '';
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* 异步检查路由权限
|
|
1422
|
+
* @param {Object} user 用户
|
|
1423
|
+
* @param {string} path 路径
|
|
1424
|
+
* @param {string} method 方法
|
|
1425
|
+
* @returns {Promise<string>} 结果
|
|
1426
|
+
*/
|
|
1427
|
+
Power.prototype._checkRoleAsync = async function (user, allowed_methods) {
|
|
1428
|
+
if (!allowed_methods.roles) {
|
|
1429
|
+
return null;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
const req_roles = Array.isArray(allowed_methods.roles)
|
|
1433
|
+
? allowed_methods.roles
|
|
1434
|
+
: [allowed_methods.roles];
|
|
1435
|
+
|
|
1436
|
+
for (const role of req_roles) {
|
|
1437
|
+
const result = await this.checkRoleAsync(user, role);
|
|
1438
|
+
if (result === '') {
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
return `缺少所需角色权限: ${req_roles.join(', ')}`;
|
|
1444
|
+
};
|
|
1445
|
+
|
|
1446
|
+
Power.prototype._checkGroupAsync = async function (user, allowed_methods) {
|
|
1447
|
+
if (!allowed_methods.groups) {
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
const req_groups = Array.isArray(allowed_methods.groups)
|
|
1452
|
+
? allowed_methods.groups
|
|
1453
|
+
: [allowed_methods.groups];
|
|
1454
|
+
|
|
1455
|
+
for (const group of req_groups) {
|
|
1456
|
+
const result = await this.checkGroupAsync(user, group);
|
|
1457
|
+
if (result === '') {
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
return `缺少所需用户组权限: ${req_groups.join(', ')}`;
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
Power.prototype._checkAdminAsyncPerm = async function (user, allowed_methods) {
|
|
1466
|
+
if (!allowed_methods.admins) {
|
|
1467
|
+
return null;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
const req_admins = Array.isArray(allowed_methods.admins)
|
|
1471
|
+
? allowed_methods.admins
|
|
1472
|
+
: [allowed_methods.admins];
|
|
1473
|
+
|
|
1474
|
+
for (const admin of req_admins) {
|
|
1475
|
+
const result = await this.checkAdminAsync(user, admin);
|
|
1476
|
+
if (result === '') {
|
|
1477
|
+
return null;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
return `缺少所需管理组权限: ${req_admins.join(', ')}`;
|
|
1482
|
+
};
|
|
1483
|
+
|
|
1484
|
+
Power.prototype.checkRouteAsync = async function (user, path, method = 'GET') {
|
|
1485
|
+
if (!user) {
|
|
1486
|
+
throw new TypeError('用户是必需的');
|
|
1487
|
+
}
|
|
1488
|
+
if (!path) {
|
|
1489
|
+
throw new TypeError('路径是必需的');
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// 如果user是字符串,则认为是用户ID,需要通过getUserAsync获取用户对象
|
|
1493
|
+
const userObj = await this._getUserIfNeeded(user);
|
|
1494
|
+
if (typeof user === 'string' && !userObj) {
|
|
1495
|
+
return '用户不存在';
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
// 转换用户数据到内部标准格式
|
|
1499
|
+
const std_user = this._transformUser(userObj);
|
|
1500
|
+
|
|
1501
|
+
// 查找匹配的路由配置
|
|
1502
|
+
const route_cfg = this._findRouteConfig(path);
|
|
1503
|
+
if (!route_cfg) {
|
|
1504
|
+
return ''; // 无路由配置,默认允许
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
// 检查方法权限
|
|
1508
|
+
const method_result = this._checkMethod(route_cfg, method);
|
|
1509
|
+
if (typeof method_result === 'string') {
|
|
1510
|
+
return method_result;
|
|
1511
|
+
}
|
|
1512
|
+
const allowed_methods = method_result;
|
|
1513
|
+
|
|
1514
|
+
// 异步检查所有权限类型
|
|
1515
|
+
const result = await this._checkRouteAsync(std_user, allowed_methods);
|
|
1516
|
+
if (result) {
|
|
1517
|
+
return result;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
return '';
|
|
1521
|
+
};
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* 异步检查所有路由权限
|
|
1525
|
+
* @param {Object} user 用户
|
|
1526
|
+
* @param {Object} allowed_methods 允许的方法
|
|
1527
|
+
* @returns {Promise<string>} 结果
|
|
1528
|
+
*/
|
|
1529
|
+
Power.prototype._checkRouteAsync = async function (user, allowed_methods) {
|
|
1530
|
+
const checks = [
|
|
1531
|
+
() => this._checkRoleAsyncWrap(user, allowed_methods),
|
|
1532
|
+
() => this._checkGroupAsyncWrap(user, allowed_methods),
|
|
1533
|
+
() => this._checkAdmAsyncPW(user, allowed_methods),
|
|
1534
|
+
() => this._checkDataScope(user, allowed_methods)
|
|
1535
|
+
];
|
|
1536
|
+
|
|
1537
|
+
for (const check of checks) {
|
|
1538
|
+
const result = await check();
|
|
1539
|
+
if (result) {
|
|
1540
|
+
return result;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
return null;
|
|
1544
|
+
};
|
|
1545
|
+
|
|
1546
|
+
Power.prototype._checkRoleAsyncWrap = async function (user, allowed_methods) {
|
|
1547
|
+
return await this._checkRoleAsync(user, allowed_methods);
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1550
|
+
Power.prototype._checkGroupAsyncWrap = async function (user, allowed_methods) {
|
|
1551
|
+
return await this._checkGroupAsync(user, allowed_methods);
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
Power.prototype._checkAdmAsyncPW = async function (user, allowed_methods) {
|
|
1555
|
+
return await this._checkAdminAsyncPerm(user, allowed_methods);
|
|
1556
|
+
};
|
|
1557
|
+
|
|
1558
|
+
/**
|
|
1559
|
+
* 异步获取用户
|
|
1560
|
+
* @param {string} user_id 用户ID
|
|
1561
|
+
* @returns {Promise<Object>} 用户
|
|
1562
|
+
*/
|
|
1563
|
+
Power.prototype.getUserAsync = async function (user_id) {
|
|
1564
|
+
if (!this._loader) {
|
|
1565
|
+
throw new Error('异步加载器未设置');
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
const cache_key = `user:${user_id}`;
|
|
1569
|
+
const cached = this._store('cache').get(cache_key);
|
|
1570
|
+
if (cached) {
|
|
1571
|
+
return cached;
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
const user = await this._loader('user', user_id);
|
|
1575
|
+
this._store('cache').set(cache_key, user);
|
|
1576
|
+
return user;
|
|
1577
|
+
};
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* 异步检查权限
|
|
1581
|
+
* @param {string} user_id 用户ID
|
|
1582
|
+
* @param {Object} power 权限
|
|
1583
|
+
* @param {Function} func 函数
|
|
1584
|
+
* @param {number} way 方式
|
|
1585
|
+
* @returns {Promise<string>} 结果
|
|
1586
|
+
*/
|
|
1587
|
+
Power.prototype.checkAsync = async function (
|
|
1588
|
+
user_id,
|
|
1589
|
+
power = {},
|
|
1590
|
+
func = null,
|
|
1591
|
+
way = 0
|
|
1592
|
+
) {
|
|
1593
|
+
const user = await this.getUserAsync(user_id);
|
|
1594
|
+
if (!user) {
|
|
1595
|
+
return '用户不存在';
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
const std_user = this._transformUser(user);
|
|
1599
|
+
return await this._checkAllAsyncPerms(std_user, power);
|
|
1600
|
+
};
|
|
1601
|
+
|
|
1602
|
+
/**
|
|
1603
|
+
* 异步检查所有权限
|
|
1604
|
+
* @param {Object} user 用户
|
|
1605
|
+
* @param {Object} power 权限
|
|
1606
|
+
* @returns {Promise<string>} 结果
|
|
1607
|
+
*/
|
|
1608
|
+
Power.prototype._checkAllAsyncPerms = async function (user, power) {
|
|
1609
|
+
const checks = [
|
|
1610
|
+
{ method: '_checkAsyncPath', async: true },
|
|
1611
|
+
{ method: '_checkAsyncRole', async: true },
|
|
1612
|
+
{ method: '_checkAsyncGroup', async: true },
|
|
1613
|
+
{ method: '_checkAsyncAdmin', async: true },
|
|
1614
|
+
{ method: '_checkAsyncPower', async: false }
|
|
1615
|
+
];
|
|
1616
|
+
|
|
1617
|
+
for (const check of checks) {
|
|
1618
|
+
const result = check.async
|
|
1619
|
+
? await this[check.method](user, power)
|
|
1620
|
+
: this[check.method](user, power);
|
|
1621
|
+
if (result) {
|
|
1622
|
+
return result;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
return '';
|
|
1627
|
+
};
|
|
1628
|
+
|
|
1629
|
+
/**
|
|
1630
|
+
* 异步检查路径权限
|
|
1631
|
+
* @param {Object} user 用户
|
|
1632
|
+
* @param {Object} power 权限
|
|
1633
|
+
* @returns {Promise<string>} 结果
|
|
1634
|
+
*/
|
|
1635
|
+
Power.prototype._checkAsyncPath = async function (user, power) {
|
|
1636
|
+
if (power.path) {
|
|
1637
|
+
const path_result = await this.checkRouteAsync(
|
|
1638
|
+
user,
|
|
1639
|
+
power.path,
|
|
1640
|
+
power.method || 'GET'
|
|
1641
|
+
);
|
|
1642
|
+
if (path_result !== '') {
|
|
1643
|
+
return path_result;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
return null;
|
|
1647
|
+
};
|
|
1648
|
+
|
|
1649
|
+
/**
|
|
1650
|
+
* 异步检查角色权限
|
|
1651
|
+
* @param {Object} user 用户
|
|
1652
|
+
* @param {Object} power 权限
|
|
1653
|
+
* @returns {Promise<string>} 结果
|
|
1654
|
+
*/
|
|
1655
|
+
Power.prototype._checkAsyncRole = async function (user, power) {
|
|
1656
|
+
if (power.role) {
|
|
1657
|
+
const role_result = await this.checkRoleAsync(user, power.role);
|
|
1658
|
+
if (role_result !== '') {
|
|
1659
|
+
return role_result;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
return null;
|
|
1663
|
+
};
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* 异步检查用户组权限
|
|
1667
|
+
* @param {Object} user 用户
|
|
1668
|
+
* @param {Object} power 权限
|
|
1669
|
+
* @returns {Promise<string>} 结果
|
|
1670
|
+
*/
|
|
1671
|
+
Power.prototype._checkAsyncGroup = async function (user, power) {
|
|
1672
|
+
if (power.group) {
|
|
1673
|
+
const group_result = await this.checkGroupAsync(user, power.group);
|
|
1674
|
+
if (group_result !== '') {
|
|
1675
|
+
return group_result;
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
return null;
|
|
1679
|
+
};
|
|
1680
|
+
|
|
1681
|
+
/**
|
|
1682
|
+
* 异步检查管理组权限
|
|
1683
|
+
* @param {Object} user 用户
|
|
1684
|
+
* @param {Object} power 权限
|
|
1685
|
+
* @returns {Promise<string>} 结果
|
|
1686
|
+
*/
|
|
1687
|
+
Power.prototype._checkAsyncAdmin = async function (user, power) {
|
|
1688
|
+
if (power.admin) {
|
|
1689
|
+
const admin_result = await this.checkAdminsAsync(
|
|
1690
|
+
user,
|
|
1691
|
+
power.admin,
|
|
1692
|
+
power.way || 0
|
|
1693
|
+
);
|
|
1694
|
+
if (admin_result !== '') {
|
|
1695
|
+
return admin_result;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return null;
|
|
1699
|
+
};
|
|
1700
|
+
|
|
1701
|
+
/**
|
|
1702
|
+
* 异步检查字段权限
|
|
1703
|
+
* @param {Object} user 用户
|
|
1704
|
+
* @param {Object} power 权限
|
|
1705
|
+
* @returns {string} 结果
|
|
1706
|
+
*/
|
|
1707
|
+
Power.prototype._checkAsyncPower = function (user, power) {
|
|
1708
|
+
if (power.power) {
|
|
1709
|
+
const power_result = this.checkField(user, power.power);
|
|
1710
|
+
if (power_result !== '') {
|
|
1711
|
+
return power_result;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
return null;
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1717
|
+
/**
|
|
1718
|
+
* 匹配路由路径
|
|
1719
|
+
* @param {string} request_path 请求路径
|
|
1720
|
+
* @param {string} config_path 配置路径
|
|
1721
|
+
* @returns {boolean} 是否匹配
|
|
1722
|
+
*/
|
|
1723
|
+
Power.prototype._matchRoute = function (request_path, config_path) {
|
|
1724
|
+
if (config_path === '*') return true;
|
|
1725
|
+
if (config_path === request_path) return true;
|
|
1726
|
+
|
|
1727
|
+
// 支持通配符匹配
|
|
1728
|
+
if (config_path.includes('*')) {
|
|
1729
|
+
const regex = new RegExp('^' + config_path.replace(/\*/g, '.*') + '$');
|
|
1730
|
+
return regex.test(request_path);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
return false;
|
|
1734
|
+
};
|
|
1735
|
+
|
|
1736
|
+
/**
|
|
1737
|
+
* 检查数据范围权限
|
|
1738
|
+
* @param {Object} user_scope 用户数据范围
|
|
1739
|
+
* @param {Object} required_scope 要求数据范围
|
|
1740
|
+
* @returns {boolean} 是否有权限
|
|
1741
|
+
*/
|
|
1742
|
+
Power.prototype._checkDataScope = function (user_scope, required_scope) {
|
|
1743
|
+
// 检查部门权限
|
|
1744
|
+
if (required_scope.dept_ids) {
|
|
1745
|
+
const user_depts = user_scope.dept_ids || [];
|
|
1746
|
+
const required_depts = Array.isArray(required_scope.dept_ids)
|
|
1747
|
+
? required_scope.dept_ids
|
|
1748
|
+
: [required_scope.dept_ids];
|
|
1749
|
+
|
|
1750
|
+
let has_dept = false;
|
|
1751
|
+
for (const dept of required_depts) {
|
|
1752
|
+
if (user_depts.includes(dept)) {
|
|
1753
|
+
has_dept = true;
|
|
1754
|
+
break;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
if (!has_dept) return false;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// 检查数据权限级别
|
|
1761
|
+
if (required_scope.level && user_scope.level) {
|
|
1762
|
+
if (user_scope.level < required_scope.level) {
|
|
1763
|
+
return false;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
return true;
|
|
1768
|
+
};
|
|
1769
|
+
|
|
1770
|
+
/**
|
|
1771
|
+
* 获取路由允许的用户组
|
|
1772
|
+
* @param {string} path 路径
|
|
1773
|
+
* @param {string} method 方法
|
|
1774
|
+
* @returns {Array} 允许的用户组列表
|
|
1775
|
+
*/
|
|
1776
|
+
Power.prototype.getRouteGroups = function (path, method = 'GET') {
|
|
1777
|
+
const route_config = this._findRouteConfig(path);
|
|
1778
|
+
|
|
1779
|
+
if (!route_config) {
|
|
1780
|
+
return [];
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
const method_config = route_config.methods || {};
|
|
1784
|
+
const allowed_methods =
|
|
1785
|
+
method_config[method.toUpperCase()] || method_config['*'];
|
|
1786
|
+
|
|
1787
|
+
if (!allowed_methods || !allowed_methods.groups) {
|
|
1788
|
+
return [];
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
return Array.isArray(allowed_methods.groups)
|
|
1792
|
+
? allowed_methods.groups
|
|
1793
|
+
: [allowed_methods.groups];
|
|
1794
|
+
};
|
|
1795
|
+
|
|
1796
|
+
/**
|
|
1797
|
+
* 获取路由允许的角色
|
|
1798
|
+
* @param {string} path 路径
|
|
1799
|
+
* @param {string} method 方法
|
|
1800
|
+
* @returns {Array} 允许的角色列表
|
|
1801
|
+
*/
|
|
1802
|
+
Power.prototype.getRouteRoles = function (path, method = 'GET') {
|
|
1803
|
+
const route_config = this._findRouteConfig(path);
|
|
1804
|
+
|
|
1805
|
+
if (!route_config) {
|
|
1806
|
+
return [];
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
const method_config = route_config.methods || {};
|
|
1810
|
+
const allowed_methods =
|
|
1811
|
+
method_config[method.toUpperCase()] || method_config['*'];
|
|
1812
|
+
|
|
1813
|
+
if (!allowed_methods || !allowed_methods.roles) {
|
|
1814
|
+
return [];
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
return Array.isArray(allowed_methods.roles)
|
|
1818
|
+
? allowed_methods.roles
|
|
1819
|
+
: [allowed_methods.roles];
|
|
1820
|
+
};
|
|
1821
|
+
|
|
1822
|
+
/**
|
|
1823
|
+
* 综合权限检查
|
|
1824
|
+
* @param {Object} user 用户
|
|
1825
|
+
* @param {Object} options 选项
|
|
1826
|
+
* @returns {string} 结果
|
|
1827
|
+
*/
|
|
1828
|
+
Power.prototype.checkAll = function (user, options = {}) {
|
|
1829
|
+
if (!user) {
|
|
1830
|
+
throw new TypeError('user is required');
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
const {
|
|
1834
|
+
path,
|
|
1835
|
+
method = 'GET',
|
|
1836
|
+
role,
|
|
1837
|
+
group,
|
|
1838
|
+
admin,
|
|
1839
|
+
power = {},
|
|
1840
|
+
func = null,
|
|
1841
|
+
way = 0
|
|
1842
|
+
} = options;
|
|
1843
|
+
|
|
1844
|
+
// 检查所有权限类型
|
|
1845
|
+
const result = this._checkAllPerms(user, {
|
|
1846
|
+
path,
|
|
1847
|
+
method,
|
|
1848
|
+
role,
|
|
1849
|
+
group,
|
|
1850
|
+
admin,
|
|
1851
|
+
power,
|
|
1852
|
+
func,
|
|
1853
|
+
way
|
|
1854
|
+
});
|
|
1855
|
+
if (result) {
|
|
1856
|
+
return result;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
return '';
|
|
1860
|
+
};
|
|
1861
|
+
|
|
1862
|
+
/**
|
|
1863
|
+
* 检查所有权限类型
|
|
1864
|
+
* @param {Object} user 用户
|
|
1865
|
+
* @param {Object} options 选项
|
|
1866
|
+
* @returns {string} 结果
|
|
1867
|
+
*/
|
|
1868
|
+
Power.prototype._checkAllPerms = function (user, options) {
|
|
1869
|
+
const checks = [
|
|
1870
|
+
() => this._checkRoutePerm(user, options),
|
|
1871
|
+
() => this._checkRolePerm(user, options),
|
|
1872
|
+
() => this._checkGroupPerm(user, options),
|
|
1873
|
+
() => this._checkAdminPerm(user, options),
|
|
1874
|
+
() => this._checkFieldPerm(user, options)
|
|
1875
|
+
];
|
|
1876
|
+
|
|
1877
|
+
for (const check of checks) {
|
|
1878
|
+
const result = check();
|
|
1879
|
+
if (result) {
|
|
1880
|
+
return result;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return null;
|
|
1884
|
+
};
|
|
1885
|
+
|
|
1886
|
+
/**
|
|
1887
|
+
* 检查路由权限
|
|
1888
|
+
* @param {Object} user 用户
|
|
1889
|
+
* @param {Object} options 选项
|
|
1890
|
+
* @returns {string} 结果
|
|
1891
|
+
*/
|
|
1892
|
+
Power.prototype._checkRoutePerm = function (user, options) {
|
|
1893
|
+
if (options.path) {
|
|
1894
|
+
const route_result = this.checkRoute(user, options.path, options.method);
|
|
1895
|
+
if (route_result) {
|
|
1896
|
+
return route_result;
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
return null;
|
|
1900
|
+
};
|
|
1901
|
+
|
|
1902
|
+
/**
|
|
1903
|
+
* 检查角色权限
|
|
1904
|
+
* @param {Object} user 用户
|
|
1905
|
+
* @param {Object} options 选项
|
|
1906
|
+
* @returns {string} 结果
|
|
1907
|
+
*/
|
|
1908
|
+
Power.prototype._checkRolePerm = function (user, options) {
|
|
1909
|
+
if (options.role) {
|
|
1910
|
+
const role_result = this.checkRole(user, options.role);
|
|
1911
|
+
if (role_result) {
|
|
1912
|
+
return role_result;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
return null;
|
|
1916
|
+
};
|
|
1917
|
+
|
|
1918
|
+
/**
|
|
1919
|
+
* 检查用户组权限
|
|
1920
|
+
* @param {Object} user 用户
|
|
1921
|
+
* @param {Object} options 选项
|
|
1922
|
+
* @returns {string} 结果
|
|
1923
|
+
*/
|
|
1924
|
+
Power.prototype._checkGroupPerm = function (user, options) {
|
|
1925
|
+
if (options.group) {
|
|
1926
|
+
const group_result = this.checkGroup(user, options.group);
|
|
1927
|
+
if (group_result) {
|
|
1928
|
+
return group_result;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
return null;
|
|
1932
|
+
};
|
|
1933
|
+
|
|
1934
|
+
/**
|
|
1935
|
+
* 检查管理组权限
|
|
1936
|
+
* @param {Object} user 用户
|
|
1937
|
+
* @param {Object} options 选项
|
|
1938
|
+
* @returns {string} 结果
|
|
1939
|
+
*/
|
|
1940
|
+
Power.prototype._checkAdminPerm = function (user, options) {
|
|
1941
|
+
if (options.admin) {
|
|
1942
|
+
const admin_result = this.checkAdmins(user, options.admin, options.way);
|
|
1943
|
+
if (admin_result) {
|
|
1944
|
+
return admin_result;
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
return null;
|
|
1948
|
+
};
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* 检查字段权限
|
|
1952
|
+
* @param {Object} user 用户
|
|
1953
|
+
* @param {Object} options 选项
|
|
1954
|
+
* @returns {string} 结果
|
|
1955
|
+
*/
|
|
1956
|
+
Power.prototype._checkFieldPerm = function (user, options) {
|
|
1957
|
+
const field_result = this.checkField(
|
|
1958
|
+
user,
|
|
1959
|
+
options.power,
|
|
1960
|
+
options.func,
|
|
1961
|
+
options.way
|
|
1962
|
+
);
|
|
1963
|
+
if (field_result) {
|
|
1964
|
+
return field_result;
|
|
1965
|
+
}
|
|
1966
|
+
return null;
|
|
1967
|
+
};
|
|
1968
|
+
|
|
1969
|
+
module.exports = Power;
|