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/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;