@kne/fastify-account 1.0.0-alpha.15 → 1.0.0-alpha.17

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 CHANGED
@@ -22,7 +22,7 @@ npm i --save @kne/fastify-account
22
22
  ### API
23
23
 
24
24
  ---
25
- title: "@kne/fastify-account v1.0.0-alpha.15"
25
+ title: "@kne/fastify-account v1.0.0-alpha.16"
26
26
  language_tabs:
27
27
  - shell: Shell
28
28
  - http: HTTP
@@ -42,7 +42,7 @@ headingLevel: 2
42
42
 
43
43
  <!-- Generator: Widdershins v4.0.1 -->
44
44
 
45
- <h1 id="-kne-fastify-account">@kne/fastify-account v1.0.0-alpha.15</h1>
45
+ <h1 id="-kne-fastify-account">@kne/fastify-account v1.0.0-alpha.16</h1>
46
46
 
47
47
  > Scroll down for code samples, example requests and responses. Select a language for code samples from the tabs above or the mobile navigation menu.
48
48
 
@@ -6,7 +6,7 @@ module.exports = fp(async (fastify, options) => {
6
6
  {
7
7
  schema: {
8
8
  tags: ['账号'],
9
- summary: '发送邮箱验证码',
9
+ summary: '发送登录邮箱验证码',
10
10
  body: {
11
11
  type: 'object',
12
12
  required: ['email'],
@@ -32,7 +32,7 @@ module.exports = fp(async (fastify, options) => {
32
32
  },
33
33
  async request => {
34
34
  const { email } = request.body;
35
- const code = await services.account.sendEmailCode({ email });
35
+ const code = await services.account.sendVerificationCode({ name: email, type: 0, messageType: 1 });
36
36
  return options.isTest ? { code } : {};
37
37
  }
38
38
  );
@@ -42,7 +42,7 @@ module.exports = fp(async (fastify, options) => {
42
42
  {
43
43
  schema: {
44
44
  tags: ['账号'],
45
- summary: '发送短信验证码',
45
+ summary: '发送登录短信验证码',
46
46
  body: {
47
47
  type: 'object',
48
48
  required: ['phone'],
@@ -68,7 +68,7 @@ module.exports = fp(async (fastify, options) => {
68
68
  },
69
69
  async request => {
70
70
  const { phone } = request.body;
71
- const code = await services.account.sendSMSCode({ phone });
71
+ const code = await services.account.sendVerificationCode({ name: phone, type: 0, messageType: 0 });
72
72
  return options.isTest ? { code } : {};
73
73
  }
74
74
  );
@@ -84,7 +84,7 @@ module.exports = fp(async (fastify, options) => {
84
84
  required: ['name', 'type', 'code'],
85
85
  properties: {
86
86
  name: { type: 'string', description: '被验证的账号,手机或邮箱' },
87
- type: { type: 'number', description: '0:手机注册,1:邮箱注册,2:手机登录,3:邮箱登录,4:验证租户管理员' },
87
+ type: { type: 'number', description: '0:注册,2:登录,4:验证租户管理员,5:忘记密码' },
88
88
  code: { type: 'string', description: '接受到的验证码' }
89
89
  }
90
90
  },
@@ -253,4 +253,135 @@ module.exports = fp(async (fastify, options) => {
253
253
  return { token, currentTenantId: user.currentTenantId };
254
254
  }
255
255
  );
256
+
257
+ fastify.post(
258
+ `${options.prefix}/modifyPassword`,
259
+ {
260
+ schema: {
261
+ tags: ['账号'],
262
+ summary: '新用户重置新密码',
263
+ body: {
264
+ oneOf: [
265
+ {
266
+ type: 'object',
267
+ required: ['email', 'newPwd', 'oldPwd'],
268
+ properties: {
269
+ email: { type: 'string', description: '邮箱' },
270
+ newPwd: { type: 'string', description: '新密码' },
271
+ oldPwd: { type: 'string', description: '原密码' }
272
+ }
273
+ },
274
+ {
275
+ type: 'object',
276
+ required: ['phone', 'newPwd', 'oldPwd'],
277
+ properties: {
278
+ phone: { type: 'string', description: '手机号' },
279
+ newPwd: { type: 'string', description: '新密码' },
280
+ oldPwd: { type: 'string', description: '原密码' }
281
+ }
282
+ }
283
+ ]
284
+ }
285
+ }
286
+ },
287
+ async request => {
288
+ await services.account.modifyPassword(request.body);
289
+ return {};
290
+ }
291
+ );
292
+
293
+ fastify.post(
294
+ `${options.prefix}/resetPassword`,
295
+ {
296
+ schema: {
297
+ tags: ['账号'],
298
+ summary: '用户重置密码',
299
+ body: {
300
+ oneOf: [
301
+ {
302
+ type: 'object',
303
+ required: ['email', 'newPwd', 'token'],
304
+ properties: {
305
+ email: { type: 'string', description: '邮箱' },
306
+ newPwd: { type: 'string', description: '新密码' },
307
+ token: { type: 'string', description: '验证token' }
308
+ }
309
+ },
310
+ {
311
+ type: 'object',
312
+ required: ['phone', 'newPwd'],
313
+ properties: {
314
+ phone: { type: 'string', description: '手机号' },
315
+ newPwd: { type: 'string', description: '新密码' },
316
+ token: { type: 'string', description: '验证token' }
317
+ }
318
+ }
319
+ ]
320
+ }
321
+ }
322
+ },
323
+ async request => {
324
+ await services.account.resetPassword({
325
+ email: request.body.email,
326
+ password: request.body.newPwd,
327
+ token: request.body.token
328
+ });
329
+
330
+ return {};
331
+ }
332
+ );
333
+
334
+ fastify.post(
335
+ `${options.prefix}/forgetPwd`,
336
+ {
337
+ schema: {
338
+ tags: ['账号'],
339
+ summary: '忘记密码',
340
+ body: {
341
+ oneOf: [
342
+ {
343
+ type: 'object',
344
+ required: ['email'],
345
+ properties: {
346
+ email: { type: 'string', description: '邮箱' }
347
+ }
348
+ },
349
+ {
350
+ type: 'object',
351
+ required: ['phone'],
352
+ properties: {
353
+ phone: { type: 'string', description: '手机号' }
354
+ }
355
+ }
356
+ ]
357
+ }
358
+ }
359
+ },
360
+ async request => {
361
+ const name = request.body.email || request.body.phone;
362
+ const token = await services.account.sendJWTVerificationCode({ name, type: 5, messageType: 3 });
363
+ return options.isTest ? { token } : {};
364
+ }
365
+ );
366
+
367
+ fastify.post(
368
+ `${options.prefix}/parseResetToken`,
369
+ {
370
+ schema: {
371
+ tags: ['账号'],
372
+ summary: '通过token获取name',
373
+ body: {
374
+ type: 'object',
375
+ required: ['token'],
376
+ properties: {
377
+ token: { type: 'string' }
378
+ }
379
+ }
380
+ }
381
+ },
382
+ async request => {
383
+ const { name } = await services.account.verificationJWTCodeValidate(request.body);
384
+ return { name };
385
+ }
386
+ );
256
387
  });
@@ -7,7 +7,8 @@ module.exports = ({ DataTypes }) => {
7
7
  },
8
8
  type: {
9
9
  type: DataTypes.INTEGER,
10
- allowNull: false //0:手机注册,1:邮箱注册,2:手机登录,3:邮箱登录,4:验证租户管理员
10
+ allowNull: false,
11
+ comment: '0:注册,2:登录,4:验证租户管理员,5:忘记密码'
11
12
  },
12
13
  code: {
13
14
  type: DataTypes.STRING,
@@ -15,7 +16,8 @@ module.exports = ({ DataTypes }) => {
15
16
  },
16
17
  status: {
17
18
  type: DataTypes.INTEGER,
18
- defaultValue: 0 //0:未验证,1:已验证,2:已过期
19
+ defaultValue: 0,
20
+ comment: '0:未验证,1:已验证,2:已过期'
19
21
  }
20
22
  }
21
23
  };
@@ -51,6 +51,34 @@ module.exports = fp(async (fastify, options) => {
51
51
  };
52
52
  };
53
53
 
54
+ const modifyPassword = async ({ email, phone, oldPwd, newPwd }) => {
55
+ const user = await models.user.findOne({
56
+ where: Object.assign(
57
+ {},
58
+ email
59
+ ? {
60
+ email
61
+ }
62
+ : {
63
+ phone
64
+ },
65
+ {
66
+ status: 1
67
+ }
68
+ )
69
+ });
70
+ if (!user) {
71
+ throw new Error('新用户密码只能初始化一次');
72
+ }
73
+ if (oldPwd === newPwd) {
74
+ throw new Error('重置密码不能和初始化密码相同');
75
+ }
76
+ await passwordAuthentication({ accountId: user.userAccountId, password: oldPwd });
77
+ await resetPassword({ userId: user.uuid, password: newPwd });
78
+ user.status = 0;
79
+ await user.save();
80
+ };
81
+
54
82
  const passwordAuthentication = async ({ accountId, password }) => {
55
83
  const userAccount = await models.userAccount.findOne({
56
84
  where: {
@@ -83,16 +111,20 @@ module.exports = fp(async (fastify, options) => {
83
111
  return hash.digest('hex');
84
112
  };
85
113
 
86
- const resetPassword = async ({ userId, password }) => {
114
+ const resetPassword = async ({ password, token }) => {
115
+ const { name } = await verificationJWTCodeValidate({ token });
116
+
117
+ const isEmail = userNameIsEmail(name);
118
+
87
119
  const userInfo = await models.user.findOne({
88
- where: { uuid: userId }
120
+ where: isEmail ? { email: name } : { phone: name }
89
121
  });
90
122
  if (!userInfo) {
91
123
  throw new Error('用户不存在');
92
124
  }
93
125
  const account = await models.userAccount.create(
94
126
  Object.assign({}, await passwordEncryption(password), {
95
- belongToUserId: userId
127
+ belongToUserId: userInfo.uuid
96
128
  })
97
129
  );
98
130
 
@@ -101,21 +133,11 @@ module.exports = fp(async (fastify, options) => {
101
133
 
102
134
  const register = async ({ avatar, nickname, gender, birthday, description, phone, email, code, password, status, invitationCode }) => {
103
135
  const type = phone ? 0 : 1;
104
- const verificationCode = await models.verificationCode.findOne({
105
- where: {
106
- name: type === 0 ? phone : email,
107
- type,
108
- code,
109
- status: 1
110
- }
111
- });
112
- if (!verificationCode) {
136
+
137
+ if (!(await verificationCodeValidate({ name: type === 0 ? phone : email, type, code }))) {
113
138
  throw new Error('验证码不正确或者已经过期');
114
139
  }
115
140
 
116
- verificationCode.status = 2;
117
- await verificationCode.save();
118
-
119
141
  return await services.user.addUser({
120
142
  avatar,
121
143
  nickname,
@@ -129,30 +151,31 @@ module.exports = fp(async (fastify, options) => {
129
151
  });
130
152
  };
131
153
 
132
- const sendEmailCode = async ({ email }) => {
154
+ const generateVerificationCode = async ({ name, type }) => {
133
155
  const code = generateRandom6DigitNumber();
134
-
135
- // 这里写发送逻辑
136
-
137
156
  await models.verificationCode.update(
138
157
  {
139
158
  status: 2
140
159
  },
141
160
  {
142
161
  where: {
143
- name: email,
144
- type: 1,
162
+ name,
163
+ type,
145
164
  status: 0
146
165
  }
147
166
  }
148
167
  );
149
-
150
168
  await models.verificationCode.create({
151
- name: email,
152
- type: 1,
169
+ name,
170
+ type,
153
171
  code
154
172
  });
173
+ return code;
174
+ };
155
175
 
176
+ const sendVerificationCode = async ({ name, type, messageType }) => {
177
+ const code = await generateVerificationCode({ name, type });
178
+ // 这里写发送逻辑
156
179
  return code;
157
180
  };
158
181
 
@@ -177,40 +200,31 @@ module.exports = fp(async (fastify, options) => {
177
200
  return isPass;
178
201
  };
179
202
 
180
- const sendSMSCode = async ({ phone }) => {
181
- const code = generateRandom6DigitNumber();
182
-
203
+ const sendJWTVerificationCode = async ({ name, type, messageType }) => {
204
+ const code = await generateVerificationCode({ name, type });
205
+ const token = fastify.jwt.sign({ name, type, code });
183
206
  // 这里写发送逻辑
207
+ return token;
208
+ };
184
209
 
185
- await models.verificationCode.update(
186
- {
187
- status: 2
188
- },
189
- {
190
- where: {
191
- name: phone,
192
- type: 0,
193
- status: 0
194
- }
195
- }
196
- );
197
-
198
- await models.verificationCode.create({
199
- name: phone,
200
- type: 0,
201
- code
202
- });
203
-
204
- return code;
210
+ const verificationJWTCodeValidate = async ({ token }) => {
211
+ const { iat, name, type, code } = fastify.jwt.decode(token);
212
+ if (!(await verificationCodeValidate({ name, type, code }))) {
213
+ throw new Error('验证码不正确或者已经过期');
214
+ }
215
+ return { name, type, code };
205
216
  };
206
217
 
207
218
  services.account = {
208
219
  md5,
209
220
  login,
221
+ modifyPassword,
210
222
  register,
211
- sendEmailCode,
212
- sendSMSCode,
223
+ generateVerificationCode,
224
+ sendVerificationCode,
213
225
  verificationCodeValidate,
226
+ sendJWTVerificationCode,
227
+ verificationJWTCodeValidate,
214
228
  passwordEncryption,
215
229
  passwordAuthentication,
216
230
  resetPassword
@@ -17,8 +17,16 @@ module.exports = fp(async (fastify, options) => {
17
17
  };
18
18
 
19
19
  const addTenantOrg = async org => {
20
- if (await models.tenantOrg.count({ where: { name: org.name } })) {
21
- throw new Error('组织名称不能重复');
20
+ if (
21
+ await models.tenantOrg.count({
22
+ where: {
23
+ name: org.name,
24
+ pid: org.pid,
25
+ tenantId: org.tenantId
26
+ }
27
+ })
28
+ ) {
29
+ throw new Error('组织名称在同一父组织下有重复');
22
30
  }
23
31
 
24
32
  return await models.tenantOrg.create({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kne/fastify-account",
3
- "version": "1.0.0-alpha.15",
3
+ "version": "1.0.0-alpha.17",
4
4
  "description": "fastify的用户管理账号等实现",
5
5
  "main": "index.js",
6
6
  "scripts": {