free-be-account 0.0.1
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/crypto.js +927 -0
- package/enum.js +7 -0
- package/index.js +1002 -0
- package/package.json +15 -0
- package/routers/index.js +4 -0
- package/routers/label/index.js +4 -0
- package/routers/label/route.js +33 -0
- package/routers/mgmt/index.js +4 -0
- package/routers/mgmt/route.js +279 -0
- package/routers/org/export/index.js +4 -0
- package/routers/org/export/route.js +11 -0
- package/routers/org/index.js +4 -0
- package/routers/org/route.js +67 -0
- package/routers/perm/index.js +4 -0
- package/routers/perm/route.js +94 -0
- package/routers/uc/index.js +4 -0
- package/routers/uc/info/index.js +4 -0
- package/routers/uc/info/route.js +95 -0
- package/routers/uc/phone/index.js +5 -0
- package/routers/uc/phone/route.js +72 -0
- package/routers/uc/pwd/index.js +4 -0
- package/routers/uc/pwd/route.js +41 -0
- package/routers/uc/sub/index.js +4 -0
- package/routers/uc/sub/route.js +158 -0
- package/sms/index.js +134 -0
- package/test/index.js +1 -0
- package/utils.js +209 -0
package/index.js
ADDED
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
// 三种方式注册,简单用户名密码,不需要验证,只要不重复即可
|
|
2
|
+
// 手机号注册,验证码
|
|
3
|
+
// 邮箱注册,验证
|
|
4
|
+
|
|
5
|
+
// nodemailer send email
|
|
6
|
+
const passport = require('passport');
|
|
7
|
+
const LocalStrategy = require('passport-local').Strategy;
|
|
8
|
+
const {v1: uuidv1} = require('uuid');
|
|
9
|
+
const crypto = require("./crypto");
|
|
10
|
+
const { clearPermission, getPermissionPathList, verifyPassword, encryptPwd } = require('./utils');
|
|
11
|
+
const { AccountAuditStatus } = require('./enum');
|
|
12
|
+
const sms = require('./sms');
|
|
13
|
+
|
|
14
|
+
let __app_service_list_saved = false;
|
|
15
|
+
let __saved_service_list;
|
|
16
|
+
|
|
17
|
+
const __getServiceList = async (res, filter = { Enabled: true }) => {
|
|
18
|
+
// add app.serviceList into db if not yet
|
|
19
|
+
if (!__app_service_list_saved) {
|
|
20
|
+
await res.app.modules.account.utils.saveServiceList(res.app);
|
|
21
|
+
__app_service_list_saved = true;
|
|
22
|
+
} else {
|
|
23
|
+
return __saved_service_list;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const allPerms = await res.app.models.permission.find(filter);
|
|
27
|
+
|
|
28
|
+
const permList = {};
|
|
29
|
+
if (allPerms && allPerms.length > 0) {
|
|
30
|
+
// create permission object
|
|
31
|
+
allPerms.forEach(doc => {
|
|
32
|
+
if (!doc.Path) return;
|
|
33
|
+
|
|
34
|
+
const pathList = doc.Path.split('/');
|
|
35
|
+
let permo = permList;
|
|
36
|
+
for (let i = 0; i < pathList.length; i += 1) {
|
|
37
|
+
const pl = pathList[i];
|
|
38
|
+
if (!pl) continue;
|
|
39
|
+
permo[pl] = permo[pl] || {};
|
|
40
|
+
permo = permo[pl];
|
|
41
|
+
|
|
42
|
+
if (i >= pathList.length - 1) {
|
|
43
|
+
Object.assign(permo, {
|
|
44
|
+
Title: doc.Title,
|
|
45
|
+
Description: doc.Description,
|
|
46
|
+
Index: doc.Index,
|
|
47
|
+
Scope: doc.Scope.map(sc => {
|
|
48
|
+
const dso = res.app.getContainerContent('DataScope').find(ds => ds.Name === sc.Name);
|
|
49
|
+
return {
|
|
50
|
+
Label: dso ? dso.Label : '',
|
|
51
|
+
Field: `${sc.Name}`,
|
|
52
|
+
Type: 'Select',
|
|
53
|
+
Options: dso ? dso.Options : []
|
|
54
|
+
}
|
|
55
|
+
}),
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
__saved_service_list = permList;
|
|
63
|
+
|
|
64
|
+
return permList;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 检验接口调用权限。
|
|
69
|
+
*
|
|
70
|
+
* @param app
|
|
71
|
+
* @param user_permission
|
|
72
|
+
* @param api_path
|
|
73
|
+
* @returns {boolean}
|
|
74
|
+
*/
|
|
75
|
+
const verify_api_permission = async (app, mdl, user, api_path) => {
|
|
76
|
+
const service_list = await __getServiceList({ app });
|
|
77
|
+
if (!service_list || Object.keys(service_list).length <= 0) return false;
|
|
78
|
+
|
|
79
|
+
const user_permission = user ? user.Permission : {};
|
|
80
|
+
|
|
81
|
+
if (user_permission === '*') return true;
|
|
82
|
+
|
|
83
|
+
if (!service_list) return false;
|
|
84
|
+
if (!user_permission) return false;
|
|
85
|
+
|
|
86
|
+
// hooks from other modules
|
|
87
|
+
const customizedList = ((mdl.config && mdl.config['customizeControlList']) || []);
|
|
88
|
+
for (let i = 0; i < customizedList.length; i += 1) {
|
|
89
|
+
const cl = customizedList[i];
|
|
90
|
+
|
|
91
|
+
if (typeof cl !== 'object') continue;
|
|
92
|
+
if (!cl.pattern || !cl.replace) continue;
|
|
93
|
+
|
|
94
|
+
if (typeof cl.pattern === 'string')
|
|
95
|
+
api_path = api_path.replace(cl.pattern, cl.replace);
|
|
96
|
+
|
|
97
|
+
if (typeof cl.pattern === 'object')
|
|
98
|
+
api_path = api_path.replace(new RegExp(cl.pattern), cl.replace);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const qIndex = api_path.indexOf('?')
|
|
102
|
+
if (qIndex > 0) api_path = api_path.substr(0, qIndex)
|
|
103
|
+
if (api_path.startsWith('/api/')) api_path = api_path.slice('/api/'.length);
|
|
104
|
+
if (api_path.startsWith('api/')) api_path = api_path.slice('api/'.length);
|
|
105
|
+
const api_service_list = api_path.split('/');
|
|
106
|
+
let service = service_list;
|
|
107
|
+
let user_service = typeof user_permission === 'string' ? JSON.parse(user_permission.replace(/'/g, '"')) : user_permission;
|
|
108
|
+
|
|
109
|
+
// check permission
|
|
110
|
+
for (let i = 0; i < api_service_list.length; ++i) {
|
|
111
|
+
const api_service = api_service_list[i];
|
|
112
|
+
|
|
113
|
+
if (api_service !== '') {
|
|
114
|
+
if (service[api_service]) {
|
|
115
|
+
if (!user_service[api_service]) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
service = service[api_service];
|
|
120
|
+
user_service = user_service[api_service];
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return true; // TODO: secure enough??
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
module.exports = {
|
|
132
|
+
sms,
|
|
133
|
+
AccountAuditStatus,
|
|
134
|
+
config: {
|
|
135
|
+
routeRoot: 'account',
|
|
136
|
+
asRouteService: true,
|
|
137
|
+
defaultPassword: '12345678',
|
|
138
|
+
subAccountsHaveSameDateScope: true,
|
|
139
|
+
subAccountsHaveSubAccountsPermission: false,
|
|
140
|
+
|
|
141
|
+
accountRequireAudit: true,
|
|
142
|
+
accountDefaultPermissions: {},
|
|
143
|
+
accountDefaultPassword: '12345678',
|
|
144
|
+
accountDefaultPasswordRandom: false,
|
|
145
|
+
accountDefaultPasswordRandomLength: 6,
|
|
146
|
+
// accountDefaultPermissions: [
|
|
147
|
+
// // could from system config
|
|
148
|
+
// // {
|
|
149
|
+
// // condition: {},
|
|
150
|
+
// // permission: {}
|
|
151
|
+
// // }
|
|
152
|
+
// ],
|
|
153
|
+
whiteList: [],
|
|
154
|
+
userWhiteList: [],
|
|
155
|
+
customizeControlList: [],
|
|
156
|
+
keepTokenAccounts: ['demo'],
|
|
157
|
+
strategy: 'local',
|
|
158
|
+
defaultAccountName: 'admin',
|
|
159
|
+
defaultAccountPwd: 'adminadmin',
|
|
160
|
+
pwdEncryptMethod: ['sha1', 'bcrypt', 'md5'],
|
|
161
|
+
desKey: 'eis,is,s,2020',
|
|
162
|
+
|
|
163
|
+
permFields: [
|
|
164
|
+
{
|
|
165
|
+
Type: 'Category',
|
|
166
|
+
Label: '权限定义信息',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
Name: 'Index',
|
|
170
|
+
Label: '排序号',
|
|
171
|
+
Type: 'Number',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
Name: 'Name',
|
|
175
|
+
Label: '数据名称',
|
|
176
|
+
Type: 'String',
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
Name: 'Title',
|
|
180
|
+
Label: '显示名称',
|
|
181
|
+
Type: 'String',
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
Name: 'Description',
|
|
185
|
+
Label: '说明',
|
|
186
|
+
Type: 'Text',
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
|
|
190
|
+
infoStepsDefinition: [
|
|
191
|
+
{
|
|
192
|
+
Name: '用户信息',
|
|
193
|
+
Index: 1,
|
|
194
|
+
Description: [{ Status: '1', Description: '已填写' }, { Status: '-1', Description: '未填写' }, { Status: '0', Description: '未填写' }],
|
|
195
|
+
Actions: [
|
|
196
|
+
{
|
|
197
|
+
Label: '保存',
|
|
198
|
+
Action: 'save',
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
Label: '提交审核',
|
|
202
|
+
Action: 'submit',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
Label: '修改',
|
|
206
|
+
Action: 'edit',
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
Fields: [
|
|
210
|
+
{
|
|
211
|
+
Type: 'Category',
|
|
212
|
+
Label: '账号信息',
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
Type: 'String',
|
|
216
|
+
Label: '登录手机号',
|
|
217
|
+
Name: 'PhoneNumber',
|
|
218
|
+
Index: 1,
|
|
219
|
+
ReadOnly: true,
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
Type: 'Category',
|
|
223
|
+
Label: '用户信息',
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
Type: 'String',
|
|
227
|
+
Label: '姓名',
|
|
228
|
+
Name: 'Profile.Name',
|
|
229
|
+
Index: 1,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
Type: 'String',
|
|
233
|
+
Label: '昵称',
|
|
234
|
+
Name: 'Profile.NickName',
|
|
235
|
+
Index: 2,
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
Type: 'String',
|
|
239
|
+
Label: '邮箱',
|
|
240
|
+
Name: 'Profile.Email',
|
|
241
|
+
Index: 3,
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
Type: 'String',
|
|
245
|
+
Label: '职务',
|
|
246
|
+
Name: 'Profile.Title',
|
|
247
|
+
Index: 4,
|
|
248
|
+
},
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
],
|
|
252
|
+
|
|
253
|
+
sms: {
|
|
254
|
+
platform: '',
|
|
255
|
+
keys: {}
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
dependencies: [
|
|
259
|
+
'core-modules'
|
|
260
|
+
]
|
|
261
|
+
},
|
|
262
|
+
data: {
|
|
263
|
+
account: {
|
|
264
|
+
// account could have sub accounts
|
|
265
|
+
Parent: { type: 'ID', refer: 'account' },
|
|
266
|
+
|
|
267
|
+
// local login user name and password
|
|
268
|
+
PhoneNumber: { type: 'String', unique: true, sparse: true },
|
|
269
|
+
UserName: { type: 'String', unique: true, sparse: true },
|
|
270
|
+
Password: { type: 'String' },
|
|
271
|
+
|
|
272
|
+
// 3rd party login token
|
|
273
|
+
Secret: { type: 'String', unique: true, sparse: true },
|
|
274
|
+
|
|
275
|
+
// more info saved in profile
|
|
276
|
+
Profile: { type: 'Object' },
|
|
277
|
+
|
|
278
|
+
Enabled: { type: 'Boolean', default: true },
|
|
279
|
+
|
|
280
|
+
Permission: { type: 'Object', default: {} },
|
|
281
|
+
|
|
282
|
+
// Audit status
|
|
283
|
+
Status: { type: 'String' },
|
|
284
|
+
|
|
285
|
+
Org: { type: 'ID', refer: 'organization' },
|
|
286
|
+
|
|
287
|
+
Labels: { type: 'Array', default: [] }
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
organization: {
|
|
291
|
+
Parent: { type: 'ID', refer: 'organization' },
|
|
292
|
+
Name: { type: 'String', required: true },
|
|
293
|
+
Description: { type: 'String' },
|
|
294
|
+
Index: { type: 'Number', required: true },
|
|
295
|
+
IsVirtual: { type: 'Boolean', default: false },
|
|
296
|
+
|
|
297
|
+
Permission: { type: 'Object', default: {} },
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
permission: {
|
|
301
|
+
Parent: { type: "ID", refer: 'permission' },
|
|
302
|
+
Name: { type: 'String' },
|
|
303
|
+
Title: { type: 'String' },
|
|
304
|
+
Description: { type: 'String' },
|
|
305
|
+
Path: { type: 'String' },
|
|
306
|
+
Index: { type: 'Number', required: true },
|
|
307
|
+
Enabled: { type: 'Boolean', required: true, default: true },
|
|
308
|
+
BuiltIn: { type: "Boolean", required: true, default: true },
|
|
309
|
+
Scope: [
|
|
310
|
+
{
|
|
311
|
+
Name: { type: 'String', required: true },
|
|
312
|
+
Params: { type: 'Array' },
|
|
313
|
+
}
|
|
314
|
+
],
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
plabel: {
|
|
318
|
+
Name: { type: 'String', required: true, unique: true },
|
|
319
|
+
Description: { type: 'String' },
|
|
320
|
+
Index: { type: 'Number', required: true },
|
|
321
|
+
Enabled: { type: 'Boolean', default: true },
|
|
322
|
+
Permission: { type: 'Object', default: {} },
|
|
323
|
+
|
|
324
|
+
// label could be nagtive, means a user with it will DO NOT has it's permissions
|
|
325
|
+
Negative: { type: 'Boolean', default: false },
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
utils: {
|
|
329
|
+
verify_api_permission,
|
|
330
|
+
...require('./utils')
|
|
331
|
+
},
|
|
332
|
+
hasPermission: async (req, mdl) => {
|
|
333
|
+
// compare user permissions, completed permissions, and this api path
|
|
334
|
+
// all the other APIs
|
|
335
|
+
let access_token = req.cookies.token || req.header('Authorization');
|
|
336
|
+
let cacheData = (await req.app.cache.get(access_token)) || {};
|
|
337
|
+
|
|
338
|
+
let id = cacheData.userId;
|
|
339
|
+
let user;
|
|
340
|
+
|
|
341
|
+
// 用来做第三方集成身份认证的字段
|
|
342
|
+
let userid = req.body.UserId || req.header('UserId');
|
|
343
|
+
let appid = req.body.AppId || req.header('AppId');
|
|
344
|
+
let ts = req.body.Timestamp || req.header('Timestamp');
|
|
345
|
+
// md5(JSON.stringify({Timestamp:xxx, UserId: xxx, UserSecret:xxx }))
|
|
346
|
+
let sign = req.body.Sign || req.header('Sign');
|
|
347
|
+
|
|
348
|
+
// if (cacheData.type === 'wx') {
|
|
349
|
+
// // login with wechat
|
|
350
|
+
// user = await User.findOne({ WxOpenId: id }).lean();
|
|
351
|
+
// }
|
|
352
|
+
// else
|
|
353
|
+
if (cacheData.type === 'pwd') {
|
|
354
|
+
// login with username/email/phone and password
|
|
355
|
+
user = await req.app.models['account'].findOne({ id: id, Enabled: true, Deleted: false });
|
|
356
|
+
}
|
|
357
|
+
else if (userid && appid && sign && ts) {
|
|
358
|
+
// 第三方系统集成
|
|
359
|
+
const tmpUser = await req.app.models['account'].findOne({ id: userid, Enabled: true, Deleted: false });
|
|
360
|
+
|
|
361
|
+
if (!tmpUser) {
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const tmpSign = crypto.MD5(JSON.stringify({
|
|
366
|
+
Timestamp: ts,
|
|
367
|
+
UserId: userid,
|
|
368
|
+
UserSecret: tmpUser.Secret
|
|
369
|
+
}));
|
|
370
|
+
|
|
371
|
+
if (tmpSign !== sign) {
|
|
372
|
+
req.app.logger.debug('user: ' + userid + ',sign: ' + sign + ',ts:' + ts + ',realSign: ' + tmpSign);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// 检查请求时间
|
|
377
|
+
if (tmpUser.LastCallTimestamp && tmpUser.LastCallTimestamp >= ts) {
|
|
378
|
+
// 上次请求时间大于当前时间戳
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// 身份验证通过
|
|
383
|
+
tmpUser.isIntegration = true;
|
|
384
|
+
user = tmpUser;
|
|
385
|
+
|
|
386
|
+
// 更新时间戳
|
|
387
|
+
tmpUser.LastCallTimestamp = ts;
|
|
388
|
+
await tmpUser.save();
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (!user) {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
await req.app.cache.put(access_token, { userId: id, type: cacheData.type }, req.app.config['cacheTimeout']);
|
|
399
|
+
// cache.put(access_token, { userId: id, type: cacheData.type }, req.app.config['cacheTimeout']);
|
|
400
|
+
req.user = user;
|
|
401
|
+
|
|
402
|
+
// check user white list, urls in which will be public for all the login users
|
|
403
|
+
const whiteList = ((mdl.config && mdl.config['userWhiteList']) || []);
|
|
404
|
+
for (let i = 0; i < whiteList.length; i += 1) {
|
|
405
|
+
const wl = whiteList[i];
|
|
406
|
+
|
|
407
|
+
if (typeof wl === 'string' && wl.toLowerCase() === req.originalUrl.toLowerCase()) return true;
|
|
408
|
+
|
|
409
|
+
if (typeof wl === 'object' && new RegExp(wl).test(req.originalUrl)) return true;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// clear sub account permission for all sub accounts
|
|
413
|
+
if(!mdl.config.subAccountsHaveSubAccountsPermission && req.user && req.user.Parent && req.user.Permission && req.user.Permission.uc && req.user.Permission.uc.sub){
|
|
414
|
+
delete req.user.Permission.uc.sub;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// if has permission to access the API, then call next
|
|
418
|
+
const hasPerm = await mdl.utils.verify_api_permission(req.app, mdl, user, req.originalUrl);
|
|
419
|
+
if (!!req.originalUrl && hasPerm)
|
|
420
|
+
return true;
|
|
421
|
+
|
|
422
|
+
// otherwise return error
|
|
423
|
+
return false;
|
|
424
|
+
},
|
|
425
|
+
i18n: {
|
|
426
|
+
'en-us': {
|
|
427
|
+
'module-title': 'Account',
|
|
428
|
+
'module-description': 'Manage all the accounts and related features in the system.',
|
|
429
|
+
|
|
430
|
+
'module-mgmt-title': 'Account management',
|
|
431
|
+
'module-mgmt-description': 'Manage all the accounts in the system.',
|
|
432
|
+
|
|
433
|
+
'module-org-title': 'Organization management',
|
|
434
|
+
'module-org-description': 'Manage all the organizations in the system.',
|
|
435
|
+
'module-org-export-title': 'Export Organization',
|
|
436
|
+
'module-org-export-description': 'Export all the organizations from the system.',
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
'module-perm-title': 'Permission management',
|
|
440
|
+
'module-perm-description': 'Manage all the permission definitions in the system.',
|
|
441
|
+
'scope-field-label': 'Data Scope',
|
|
442
|
+
'scope-params-header-label': 'Data Scope',
|
|
443
|
+
'scope-params-label': 'Params',
|
|
444
|
+
|
|
445
|
+
'Org Based Data Scope': 'Organization based data scope',
|
|
446
|
+
'Data scope base on the organization':'Data scope base on the organization',
|
|
447
|
+
'Self':'Self',
|
|
448
|
+
'My Org': 'The organization',
|
|
449
|
+
'All': 'All',
|
|
450
|
+
'Account Field':'Account field',
|
|
451
|
+
'Org Field':'Organization field',
|
|
452
|
+
|
|
453
|
+
'module-label-title': 'Permission Label management',
|
|
454
|
+
'module-label-description': 'Manage all the permission labels in the system.',
|
|
455
|
+
|
|
456
|
+
'module-uc-title': 'User Center',
|
|
457
|
+
'module-uc-description': '',
|
|
458
|
+
'module-uc-sub-title': 'Sub Account',
|
|
459
|
+
'module-uc-sub-description': '',
|
|
460
|
+
},
|
|
461
|
+
'zh-cn': {
|
|
462
|
+
'module-title': '账号管理',
|
|
463
|
+
'module-description': '统一管理系统中的账号以及相关功能。',
|
|
464
|
+
|
|
465
|
+
'module-mgmt-title': '管理',
|
|
466
|
+
'module-mgmt-description': '统一管理系统中的账号。',
|
|
467
|
+
|
|
468
|
+
'module-org-title': '组织机构管理',
|
|
469
|
+
'module-org-description': '统一管理系统中的组织机构。',
|
|
470
|
+
'module-org-export-title': '导出机构',
|
|
471
|
+
'module-org-export-description': '导出系统中所有的机构配置数据。',
|
|
472
|
+
|
|
473
|
+
'module-perm-title': '权限定义管理',
|
|
474
|
+
'module-perm-description': '统一管理系统中的权限定义。',
|
|
475
|
+
'scope-field-label': '数据权限',
|
|
476
|
+
'scope-params-header-label': '数据权限',
|
|
477
|
+
'scope-params-label': '关联参数',
|
|
478
|
+
|
|
479
|
+
'Org Based Data Scope': '基于组织的数据权限',
|
|
480
|
+
'Data scope base on the organization':'基于组织机构的数据权限控制。',
|
|
481
|
+
'Self':'自己',
|
|
482
|
+
'My Org': '所在机构',
|
|
483
|
+
'All': '全部',
|
|
484
|
+
'Account Field':'代表账号的字段名',
|
|
485
|
+
'Org Field':'代表组织的字段名',
|
|
486
|
+
|
|
487
|
+
'module-label-title': '权限标签管理',
|
|
488
|
+
'module-label-description': '统一管理系统中的权限标签。',
|
|
489
|
+
|
|
490
|
+
'module-uc-title': '用户中心',
|
|
491
|
+
'module-uc-description': '',
|
|
492
|
+
'module-uc-sub-title': '子账号管理',
|
|
493
|
+
'module-uc-sub-description': '',
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
hooks: {
|
|
497
|
+
onBegin: (app) => {
|
|
498
|
+
app.use(passport.initialize());
|
|
499
|
+
},
|
|
500
|
+
onModulesReady: (app, mdl) => {
|
|
501
|
+
// register the data scope containers
|
|
502
|
+
app.registerContainer(null, 'DataScope', 'The data scope container which will contains all the data scope definitions.', (c, o) => {
|
|
503
|
+
if (!o.Options || !o.Func) {
|
|
504
|
+
app.logger.error(`Data scope ${o.name} should have options and func!!`)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return true;
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
app.addDataScope({
|
|
511
|
+
mdl: mdl,
|
|
512
|
+
Name: 'orgDataScope',
|
|
513
|
+
Label: mdl.t('Org Based Data Scope'),
|
|
514
|
+
Description: mdl.t('Data scope base on the organization'),
|
|
515
|
+
Options: [
|
|
516
|
+
{
|
|
517
|
+
Label: mdl.t('Self'),
|
|
518
|
+
Value: 'self',
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
Label: mdl.t('My Org'),
|
|
522
|
+
Value: 'org',
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
Label: mdl.t('All'),
|
|
526
|
+
Value: 'all',
|
|
527
|
+
}
|
|
528
|
+
],
|
|
529
|
+
Default: 'self',
|
|
530
|
+
Params: [
|
|
531
|
+
{
|
|
532
|
+
Label: mdl.t('Account Field'),
|
|
533
|
+
Name: 'Account',
|
|
534
|
+
Type: 'String'
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
Label: mdl.t('Org Field'),
|
|
538
|
+
Name: 'Org',
|
|
539
|
+
Type: 'String',
|
|
540
|
+
}
|
|
541
|
+
],
|
|
542
|
+
/**
|
|
543
|
+
* The function to generate the filter object base on the specified data scope
|
|
544
|
+
*/
|
|
545
|
+
Func: (scope, pScope, p) => {
|
|
546
|
+
return (req, res, next) => {
|
|
547
|
+
// add filter according to the data scope
|
|
548
|
+
let val;
|
|
549
|
+
const filter = {};
|
|
550
|
+
|
|
551
|
+
// get user data scope for the current router
|
|
552
|
+
if (req.user && req.user.Permission && p) {
|
|
553
|
+
const pList = p.split('/');
|
|
554
|
+
let perm = req.user.Permission;
|
|
555
|
+
let userScope;
|
|
556
|
+
|
|
557
|
+
for (let i = 0; i < pList.length; i += 1) {
|
|
558
|
+
const pl = pList[i];
|
|
559
|
+
|
|
560
|
+
if (pl) {
|
|
561
|
+
if (perm[pl]) {
|
|
562
|
+
perm = perm[pl];
|
|
563
|
+
if (perm.Scope) {
|
|
564
|
+
userScope = perm.Scope;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
val = userScope ? userScope['orgDataScope'] : undefined;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// make filter
|
|
573
|
+
if (typeof val !== 'undefined')
|
|
574
|
+
switch (val.toString()) {
|
|
575
|
+
case 'self':
|
|
576
|
+
if (req.user.Parent && mdl.config.subAccountsHaveSameDateScope){
|
|
577
|
+
filter[pScope.Params[0].Account] = {$in: [req.user.id, req.user.Parent]};
|
|
578
|
+
} else {
|
|
579
|
+
filter[pScope.Params[0].Account] = req.user.id;
|
|
580
|
+
}
|
|
581
|
+
res.locals.filter = Object.merge({}, res.locals.filter, filter);
|
|
582
|
+
break;
|
|
583
|
+
case 'org':
|
|
584
|
+
filter[pScope.Params[0].Org] = req.user.Org;
|
|
585
|
+
res.locals.filter = Object.merge({}, res.locals.filter, filter);
|
|
586
|
+
break;
|
|
587
|
+
default:
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return next();
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
},
|
|
596
|
+
onLoadRouters: async (app, m) => {
|
|
597
|
+
// define the local strategy
|
|
598
|
+
passport.use(new LocalStrategy(
|
|
599
|
+
function (uname, pwd, done) {
|
|
600
|
+
const username = crypto.encoder.desDecode(uname, m.config.desKey);
|
|
601
|
+
const password = crypto.encoder.desDecode(pwd, m.config.desKey);
|
|
602
|
+
app.models['account'].findOne(
|
|
603
|
+
{
|
|
604
|
+
$or: [{ PhoneNumber: username }, { UserName: username }],
|
|
605
|
+
// Password: password,
|
|
606
|
+
Enabled: true,
|
|
607
|
+
Deleted: false,
|
|
608
|
+
}, function (err, user) {
|
|
609
|
+
if (err) { return done(err); }
|
|
610
|
+
if (!user) { return done(null, false); }
|
|
611
|
+
if (!verifyPassword(password, user.Password, m.config.pwdEncryptMethod || 'md5')) { return done(null, false); }
|
|
612
|
+
return done(null, user);
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
));
|
|
616
|
+
|
|
617
|
+
// login with the specified strategy
|
|
618
|
+
app.post(`${app.config['baseUrl'] || ''}/logedin`,
|
|
619
|
+
async (req, res) => {
|
|
620
|
+
// permission control
|
|
621
|
+
if (!await m.hasPermission(req, m)) {
|
|
622
|
+
await res.endWithErr(200, 401);
|
|
623
|
+
return;
|
|
624
|
+
} else {
|
|
625
|
+
res.endWithData({});
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
// permission control
|
|
632
|
+
app.use(async (req, res, next) => {
|
|
633
|
+
// permission control
|
|
634
|
+
if (!await m.hasPermission(req, m)) {
|
|
635
|
+
const whiteList = ((m.config && m.config['whiteList']) || []).concat([`${app.config['baseUrl'] || ''}/login`]);
|
|
636
|
+
for (let i = 0; i < whiteList.length; i += 1) {
|
|
637
|
+
const wl = whiteList[i];
|
|
638
|
+
|
|
639
|
+
if (typeof wl === 'string' && wl.toLowerCase() === req.originalUrl.toLowerCase()) return next();
|
|
640
|
+
|
|
641
|
+
if (typeof wl === 'object' && new RegExp(wl).test(req.originalUrl)) return next();
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (req.user && req.user.id) {
|
|
645
|
+
await res.endWithErr(400, 401);
|
|
646
|
+
}
|
|
647
|
+
else {
|
|
648
|
+
await res.endWithErr(401);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
return next();
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
async function clear_cache_token_by_user_id (id) {
|
|
658
|
+
if (!id) return;
|
|
659
|
+
|
|
660
|
+
const cacheKeys = await app.cache.keys();
|
|
661
|
+
if (cacheKeys && cacheKeys.length) {
|
|
662
|
+
for (let i = 0; i < cacheKeys.length; i += 1) {
|
|
663
|
+
const k = cacheKeys[i];
|
|
664
|
+
|
|
665
|
+
let value = await app.cache.get(k);
|
|
666
|
+
if (value && value.userId && value.userId === id)
|
|
667
|
+
await app.cache.del(k);
|
|
668
|
+
// cache.del(k);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// cache.keys().forEach(async (k) => {
|
|
673
|
+
// let value = await app.cache.get(k);
|
|
674
|
+
// if (value && value.userId && value.userId === id)
|
|
675
|
+
// cache.del(k);
|
|
676
|
+
// });
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
async function generate_new_access_token_pwd (userId, oldToken, keepToken = '') {
|
|
680
|
+
let uuid = keepToken || uuidv1();
|
|
681
|
+
|
|
682
|
+
// remove the old one from cache
|
|
683
|
+
app.cache.del(oldToken);
|
|
684
|
+
// cache.del(oldToken);
|
|
685
|
+
await clear_cache_token_by_user_id(userId);
|
|
686
|
+
|
|
687
|
+
// add the new one to the cache
|
|
688
|
+
|
|
689
|
+
app.cache.put(uuid, { userId: userId, type: 'pwd' }, app.config['cacheTimeout']);
|
|
690
|
+
// cache.put(uuid, { userId: userId, type: 'pwd' }, app.config['cacheTimeout']);
|
|
691
|
+
|
|
692
|
+
return uuid;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// login with the specified strategy
|
|
696
|
+
app.post(`${app.config['baseUrl'] || ''}/login`,
|
|
697
|
+
passport.authenticate(m.config['strategy'] || 'local', { session: false }),
|
|
698
|
+
async (req, res, next) => {
|
|
699
|
+
|
|
700
|
+
// set token into cookie
|
|
701
|
+
let access_token = req.cookies.token || req.header('Authorization');
|
|
702
|
+
let token;
|
|
703
|
+
|
|
704
|
+
if ((req.user && req.user.UserName && m.config['keepTokenAccounts'].indexOf(req.user.UserName) >= 0) ||
|
|
705
|
+
(req.user && req.user.PhoneNumber && m.config['keepTokenAccounts'].indexOf(req.user.PhoneNumber) >= 0)) {
|
|
706
|
+
// keep token
|
|
707
|
+
const kt = await app.cache.get(`_keep_token_${req.user.id}`);
|
|
708
|
+
token = await generate_new_access_token_pwd(req.user.id, access_token, kt);
|
|
709
|
+
app.cache.set(`_keep_token_${req.user.id}`, token);
|
|
710
|
+
} else {
|
|
711
|
+
token = await generate_new_access_token_pwd(req.user.id, access_token);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
res.cookie('token', token, { maxAge: app.config['cookieTimeout'] });
|
|
715
|
+
|
|
716
|
+
res.addData({
|
|
717
|
+
Name: (req.user.Profile && req.user.Profile.Name) || req.user.PhoneNumber || req.user.UserName || '',
|
|
718
|
+
Avatar: req.user.Profile && req.user.Profile.Avatar ? req.user.Profile.Avatar : '',
|
|
719
|
+
Status: req.user.Status,
|
|
720
|
+
Org: req.user.Org,
|
|
721
|
+
}, false);
|
|
722
|
+
|
|
723
|
+
return next();
|
|
724
|
+
}
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
app.post(`${app.config['baseUrl'] || ''}/logout`,
|
|
728
|
+
(req, res, next) => {
|
|
729
|
+
let access_token = req.cookies.token || req.header('Authorization');
|
|
730
|
+
|
|
731
|
+
// call logout of the passport
|
|
732
|
+
req.logout();
|
|
733
|
+
|
|
734
|
+
// clear the cached token
|
|
735
|
+
res.clearCookie('token');
|
|
736
|
+
|
|
737
|
+
// clear cached data when the account is not in the keep token list
|
|
738
|
+
// app.cache.del(access_token);
|
|
739
|
+
if (access_token && (req.user && req.user.UserName && m.config['keepTokenAccounts'].indexOf(req.user.UserName) < 0) &&
|
|
740
|
+
(req.user && req.user.PhoneNumber && m.config['keepTokenAccounts'].indexOf(req.user.PhoneNumber) < 0)) {
|
|
741
|
+
app.cache.del(access_token);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
res.locals.data = {};
|
|
745
|
+
|
|
746
|
+
return next();
|
|
747
|
+
}
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
app.post(`${app.config['baseUrl'] || ''}/can_i`,
|
|
751
|
+
async (req, res, next) => {
|
|
752
|
+
const urls = (req.body.url || '').split(',');
|
|
753
|
+
let canDo = [];
|
|
754
|
+
|
|
755
|
+
for (let i = 0; i < urls.length; i += 1) {
|
|
756
|
+
const url = urls[i];
|
|
757
|
+
|
|
758
|
+
if (!url || !req.user || !await res.app.modules.account.utils.verify_api_permission(req.app, m, req.user, url)) {
|
|
759
|
+
canDo[i] = false;
|
|
760
|
+
} else {
|
|
761
|
+
canDo[i] = true;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (canDo.length === 1) canDo = canDo[0];
|
|
766
|
+
|
|
767
|
+
res.addData({ can: canDo });
|
|
768
|
+
|
|
769
|
+
return next();
|
|
770
|
+
}
|
|
771
|
+
);
|
|
772
|
+
|
|
773
|
+
// send sms
|
|
774
|
+
app.post(`${(app.config['baseUrl'] || '')}/register/sms`, async (req, res, next) => {
|
|
775
|
+
try {
|
|
776
|
+
if (!req.body.PhoneNumber) {
|
|
777
|
+
res.makeError(408, 'Please provide phone number!', m);
|
|
778
|
+
return next('route');
|
|
779
|
+
}
|
|
780
|
+
const phone = crypto.encoder.desDecode(req.body.PhoneNumber, m.config.desKey);
|
|
781
|
+
const result = await res.Module('sms').sendRandom(phone, undefined, true, 'register');
|
|
782
|
+
|
|
783
|
+
if (!result) {
|
|
784
|
+
res.makeError(500, 'Failed to send sms!', m);
|
|
785
|
+
return next('route');
|
|
786
|
+
}
|
|
787
|
+
} catch (ex) {
|
|
788
|
+
res.makeError(500, 'Failed to send sms!', m);
|
|
789
|
+
return next('route');
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
res.addData({});
|
|
793
|
+
return next();
|
|
794
|
+
})
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
// verfiy the sms code
|
|
798
|
+
app.post(`${(app.config['baseUrl'] || '')}/register/verify`, async (req, res, next) => {
|
|
799
|
+
if (!req.body.PhoneNumber || !req.body.code) {
|
|
800
|
+
res.makeError(409, 'Please provide phone number and the sms code!', m);
|
|
801
|
+
return next('route');
|
|
802
|
+
}
|
|
803
|
+
const phone = crypto.encoder.desDecode(req.body.PhoneNumber, m.config.desKey);
|
|
804
|
+
const result = await res.Module('sms').verify(phone, req.body.code);
|
|
805
|
+
// app.logger.debug(cache.exportJson());
|
|
806
|
+
|
|
807
|
+
if (!result) {
|
|
808
|
+
res.makeError(403, 'Code verification failed!', m);
|
|
809
|
+
return next('route');
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
res.addData({});
|
|
813
|
+
return next();
|
|
814
|
+
})
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
// verify phone number (duplication) for register
|
|
818
|
+
app.post(`${(app.config['baseUrl'] || '')}/register/verify/phone`, async (req, res, next) => {
|
|
819
|
+
if (!req.body.PhoneNumber) {
|
|
820
|
+
res.makeError(408, 'Please provide phone number!', m);
|
|
821
|
+
return next('route');
|
|
822
|
+
}
|
|
823
|
+
const phone = crypto.encoder.desDecode(req.body.PhoneNumber, m.config.desKey);
|
|
824
|
+
const exists = await res.app.models.account.findOne({
|
|
825
|
+
$or: [{ PhoneNumber: phone }, { UserName: phone }],
|
|
826
|
+
});
|
|
827
|
+
res.addData({ used: !!exists });
|
|
828
|
+
return next();
|
|
829
|
+
})
|
|
830
|
+
|
|
831
|
+
// register with username password
|
|
832
|
+
app.post(`${(app.config['baseUrl'] || '')}/register`,
|
|
833
|
+
async (req, res, next) => {
|
|
834
|
+
if (!req.body.Password || !req.body.PhoneNumber || !req.body.code) {
|
|
835
|
+
res.makeError(400, 'Please provide phone number, sms code and the password!', m);
|
|
836
|
+
return next('route');
|
|
837
|
+
}
|
|
838
|
+
const phone = crypto.encoder.desDecode(req.body.PhoneNumber, m.config.desKey);
|
|
839
|
+
const password = crypto.encoder.desDecode(req.body.Password, m.config.desKey);
|
|
840
|
+
if (password.length < 6) {
|
|
841
|
+
res.makeError(402, 'Password does not meet the requirement!', m);
|
|
842
|
+
return next('route');
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const result = await res.Module('sms').verify(phone, req.body.code);
|
|
846
|
+
|
|
847
|
+
if (!result) {
|
|
848
|
+
res.makeError(403, 'Code verification failed!', m);
|
|
849
|
+
return next('route');
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const existPhone = await res.app.models.account.countDocuments({ PhoneNumber: phone });
|
|
853
|
+
if (existPhone) {
|
|
854
|
+
res.makeError(404, 'The phone use used already!', m);
|
|
855
|
+
return next('route');
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// only create with specified fields
|
|
859
|
+
res.locals.body = {
|
|
860
|
+
PhoneNumber: phone,
|
|
861
|
+
Password: encryptPwd(password, m.config.pwdEncryptMethod || 'md5')
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (!m.config.accountRequireAudit) {
|
|
865
|
+
res.locals.body.Status = AccountAuditStatus.Passed;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
const defaultPerm = Object.assign({}, m.config.accountDefaultPermissions);
|
|
869
|
+
clearPermission(defaultPerm);
|
|
870
|
+
res.locals.body.Permission = defaultPerm;
|
|
871
|
+
|
|
872
|
+
return next();
|
|
873
|
+
},
|
|
874
|
+
app.CreateDocument('account')
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
// recover password
|
|
878
|
+
app.post(`${(app.config['baseUrl'] || '')}/recover`,
|
|
879
|
+
async (req, res, next) => {
|
|
880
|
+
if (!req.body.Password || !req.body.PhoneNumber || !req.body.code) {
|
|
881
|
+
res.makeError(400, 'Please provide phone number, sms code and the password!', m);
|
|
882
|
+
return next('route');
|
|
883
|
+
}
|
|
884
|
+
const phone = crypto.encoder.desDecode(req.body.PhoneNumber, m.config.desKey);
|
|
885
|
+
const password = crypto.encoder.desDecode(req.body.Password, m.config.desKey);
|
|
886
|
+
|
|
887
|
+
const result = await res.Module('sms').verify(phone, req.body.code);
|
|
888
|
+
|
|
889
|
+
if (!result) {
|
|
890
|
+
res.makeError(403, 'Code verification failed!', m);
|
|
891
|
+
return next('route');
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
// only create with specified fields
|
|
895
|
+
res.locals.body = {
|
|
896
|
+
Password: encryptPwd(password, m.config.pwdEncryptMethod || 'md5')
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
res.locals.filter = {
|
|
900
|
+
PhoneNumber: phone
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
return next();
|
|
904
|
+
},
|
|
905
|
+
app.UpdateDocument('account', false, (req, res) => {
|
|
906
|
+
res.locals.data = {};
|
|
907
|
+
})
|
|
908
|
+
);
|
|
909
|
+
|
|
910
|
+
// get service list base on the current user permission
|
|
911
|
+
app.get(`${app.config['baseUrl'] || ''}/_service_list`,
|
|
912
|
+
async (req, res, next) => {
|
|
913
|
+
if (!req.user || !req.user.Permission || Object.keys(req.user.Permission).length <= 0) {
|
|
914
|
+
res.addData({});
|
|
915
|
+
return next('route');
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
let filter;
|
|
919
|
+
if (req.user.Permission !== '*') {
|
|
920
|
+
const permPathList = getPermissionPathList(req.user.Permission);
|
|
921
|
+
filter = { Path: { $in: permPathList }, Enabled: true };
|
|
922
|
+
} else {
|
|
923
|
+
filter = { Enabled: true };
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
res.addData(await __getServiceList(res, filter));
|
|
927
|
+
|
|
928
|
+
return next();
|
|
929
|
+
},
|
|
930
|
+
);
|
|
931
|
+
|
|
932
|
+
// process configured data scope
|
|
933
|
+
app.use(function _data_scope_middleware_start (req, res, next) {
|
|
934
|
+
return next();
|
|
935
|
+
});
|
|
936
|
+
app.use(function _data_scope_middleware_end (req, res, next) {
|
|
937
|
+
return next();
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
const insertDataScopeMW = (p, n, mw) => {
|
|
941
|
+
// get existing flow routers markers
|
|
942
|
+
const firstIndex = app._router.stack.findIndex(r => r.name === '_data_scope_middleware_start');
|
|
943
|
+
let lastIndex = app._router.stack.findIndex(r => r.name === '_data_scope_middleware_end');
|
|
944
|
+
|
|
945
|
+
if (firstIndex < 0 || lastIndex < 0) {
|
|
946
|
+
app.logger.error('Cannot find the data scope marker middleware!!');
|
|
947
|
+
process.exit(-1);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// temp store rest middlewares
|
|
951
|
+
let restRouters = app._router.stack.splice(firstIndex + 1);
|
|
952
|
+
|
|
953
|
+
if (restRouters.findIndex(r => r.name === n) < 0) {
|
|
954
|
+
app.logger.debug(`Adding data scope mw: ${n}`)
|
|
955
|
+
Object.defineProperty(mw, 'name', { value: n });
|
|
956
|
+
app.use(`${app.config.baseUrl}${p}(/*)?`, mw);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// restore the rest middlewares
|
|
960
|
+
app._router.stack = app._router.stack.concat(restRouters);
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
const dataScopeList = app.getContainerContent('DataScope');
|
|
964
|
+
for (let i = 0; i < dataScopeList.length; i += 1) {
|
|
965
|
+
const ds = dataScopeList[i];
|
|
966
|
+
|
|
967
|
+
if (await app.models.permission.countDocuments({ "Scope.Name": ds.Name }) > 0) {
|
|
968
|
+
const sList = await app.models.permission.find({ "Scope.Name": ds.Name });
|
|
969
|
+
for (let j = 0; j < sList.length; j += 1) {
|
|
970
|
+
const service = sList[j];
|
|
971
|
+
|
|
972
|
+
if (service.Path) {
|
|
973
|
+
insertDataScopeMW(service.Path, `${service.Path.replace(/\//g, '_')}_${ds.Name}`, ds.Func(ds, service.Scope.find(ss => ss.Name === ds.Name), service.Path));
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
}
|
|
979
|
+
},
|
|
980
|
+
onRoutersReady: async (app, m) => {
|
|
981
|
+
// create default user if it's an empty db
|
|
982
|
+
if (await m.models['account'].countDocuments({}) <= 0) {
|
|
983
|
+
let perms = app.ctx.serviceList()
|
|
984
|
+
if (!clearPermission(perms)) {
|
|
985
|
+
perms = {}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
await m.models.account.create({
|
|
989
|
+
UserName: m.config.defaultAccountName || 'admin',
|
|
990
|
+
Password: crypto.MD5(m.config.defaultAccountPwd) || 'f6fdffe48c908deb0f4c3bd36c032e72',
|
|
991
|
+
Permission: perms,
|
|
992
|
+
Status: AccountAuditStatus.Passed,
|
|
993
|
+
Profile: {
|
|
994
|
+
Name: 'SuperAdmin'
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// TODO: remove service list which are in the white list
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}
|