@kne/fastify-account 1.0.0-alpha.2 → 1.0.0-alpha.20

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.
Files changed (54) hide show
  1. package/README.md +2506 -803
  2. package/index.js +61 -8
  3. package/libs/controllers/account.js +221 -37
  4. package/libs/controllers/admin.js +92 -17
  5. package/libs/controllers/adminPermission.js +188 -38
  6. package/libs/controllers/adminTenant.js +44 -257
  7. package/libs/controllers/adminTenantCompany.js +53 -0
  8. package/libs/controllers/adminTenantOrg.js +71 -0
  9. package/libs/controllers/{adminRole.js → adminTenantRole.js} +15 -12
  10. package/libs/controllers/adminTenantUser.js +169 -0
  11. package/libs/controllers/requestLog.js +77 -0
  12. package/libs/controllers/tenant.js +4 -14
  13. package/libs/controllers/tenantCompany.js +54 -0
  14. package/libs/controllers/tenantOrg.js +65 -0
  15. package/libs/controllers/tenantRole.js +219 -0
  16. package/libs/controllers/tenantUser.js +169 -0
  17. package/libs/controllers/user.js +4 -3
  18. package/libs/models/admin-role.js +4 -8
  19. package/libs/models/application.js +16 -10
  20. package/libs/models/company-info.js +25 -0
  21. package/libs/models/login-log.js +11 -9
  22. package/libs/models/permission.js +7 -9
  23. package/libs/models/request-log.js +43 -0
  24. package/libs/models/tenant-application.js +8 -10
  25. package/libs/models/tenant-org.js +5 -9
  26. package/libs/models/tenant-permission.js +7 -9
  27. package/libs/models/tenant-role-application.js +13 -13
  28. package/libs/models/tenant-role-permission.js +9 -14
  29. package/libs/models/tenant-role.js +5 -9
  30. package/libs/models/tenant-share-group-permission.js +5 -9
  31. package/libs/models/tenant-share-group.js +5 -9
  32. package/libs/models/tenant-source-user-share-group.js +5 -9
  33. package/libs/models/tenant-token.js +7 -9
  34. package/libs/models/tenant-user-org.js +11 -10
  35. package/libs/models/tenant-user-role.js +11 -10
  36. package/libs/models/tenant-user-share-group.js +6 -10
  37. package/libs/models/tenant-user.js +35 -16
  38. package/libs/models/tenant.js +17 -9
  39. package/libs/models/user-account.js +17 -9
  40. package/libs/models/user.js +27 -17
  41. package/libs/models/verification-code.js +8 -10
  42. package/libs/services/account.js +95 -71
  43. package/libs/services/admin.js +38 -122
  44. package/libs/services/application.js +170 -0
  45. package/libs/services/permission.js +161 -163
  46. package/libs/services/request-log.js +37 -0
  47. package/libs/services/tenant-company.js +54 -0
  48. package/libs/services/tenant-invite.js +62 -0
  49. package/libs/services/tenant-org.js +118 -0
  50. package/libs/services/tenant-role.js +109 -0
  51. package/libs/services/tenant-user.js +578 -0
  52. package/libs/services/tenant.js +69 -670
  53. package/libs/services/user.js +109 -33
  54. package/package.json +3 -3
@@ -1,7 +1,6 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- return sequelize.define(
3
- 'tenantToken',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
5
4
  tenantId: {
6
5
  type: DataTypes.UUID,
7
6
  allowNull: false
@@ -15,18 +14,17 @@ module.exports = (sequelize, DataTypes) => {
15
14
  type: DataTypes.INTEGER,
16
15
  allowNull: false //10:邀请用户加入租户
17
16
  },
18
- createTenantUserId: {
17
+ createdTenantUserId: {
19
18
  type: DataTypes.UUID
20
19
  }
21
20
  },
22
- {
23
- paranoid: true,
21
+ options: {
24
22
  indexes: [
25
23
  {
26
24
  unique: true,
27
- fields: ['tenantId', 'token', 'type', 'deletedAt']
25
+ fields: ['tenant_id', 'token', 'type', 'deleted_at']
28
26
  }
29
27
  ]
30
28
  }
31
- );
29
+ };
32
30
  };
@@ -1,22 +1,23 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- return sequelize.define(
3
- 'tenantUserOrg',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
4
+ id: {
5
+ type: DataTypes.INTEGER,
6
+ autoIncrement: true,
7
+ primaryKey: true
8
+ },
5
9
  tenantId: {
6
- type: DataTypes.STRING,
10
+ type: DataTypes.UUID,
7
11
  allowNull: false
8
12
  },
9
13
  tenantUserId: {
10
- type: DataTypes.STRING,
14
+ type: DataTypes.UUID,
11
15
  allowNull: false
12
16
  },
13
17
  tenantOrgId: {
14
18
  type: DataTypes.INTEGER,
15
19
  allowNull: false
16
20
  }
17
- },
18
- {
19
- paranoid: true
20
21
  }
21
- );
22
+ };
22
23
  };
@@ -1,22 +1,23 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- return sequelize.define(
3
- 'tenantUserRole',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
4
+ id: {
5
+ type: DataTypes.INTEGER,
6
+ autoIncrement: true,
7
+ primaryKey: true
8
+ },
5
9
  tenantId: {
6
- type: DataTypes.STRING,
10
+ type: DataTypes.UUID,
7
11
  allowNull: false
8
12
  },
9
13
  tenantUserId: {
10
- type: DataTypes.STRING,
14
+ type: DataTypes.UUID,
11
15
  allowNull: false
12
16
  },
13
17
  tenantRoleId: {
14
18
  type: DataTypes.INTEGER,
15
19
  allowNull: false
16
20
  }
17
- },
18
- {
19
- paranoid: true
20
21
  }
21
- );
22
+ };
22
23
  };
@@ -1,22 +1,18 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- return sequelize.define(
3
- 'tenantUserShareGroup',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
5
4
  tenantId: {
6
- type: DataTypes.STRING,
5
+ type: DataTypes.UUID,
7
6
  allowNull: false
8
7
  },
9
8
  tenantUserId: {
10
- type: DataTypes.STRING,
9
+ type: DataTypes.UUID,
11
10
  allowNull: false
12
11
  },
13
12
  tenantShareGroupId: {
14
13
  type: DataTypes.INTEGER,
15
14
  allowNull: false
16
15
  }
17
- },
18
- {
19
- paranoid: true
20
16
  }
21
- );
17
+ };
22
18
  };
@@ -1,12 +1,15 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- const tenantUser = sequelize.define(
3
- 'tenantUser',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
5
4
  id: {
6
- type: DataTypes.UUID,
7
- defaultValue: DataTypes.UUIDV4,
5
+ type: DataTypes.INTEGER,
6
+ autoIncrement: true,
8
7
  primaryKey: true
9
8
  },
9
+ uuid: {
10
+ type: DataTypes.UUID,
11
+ defaultValue: DataTypes.UUIDV4
12
+ },
10
13
  userId: {
11
14
  type: DataTypes.UUID,
12
15
  allowNull: false
@@ -36,21 +39,37 @@ module.exports = (sequelize, DataTypes) => {
36
39
  defaultValue: 0 //0:正常,11:已禁用,12:已关闭,
37
40
  }
38
41
  },
39
- {
40
- paranoid: true,
42
+ options: {
41
43
  indexes: [
42
44
  {
43
45
  unique: true,
44
- fields: ['tenantId', 'userId', 'deletedAt']
46
+ fields: ['uuid', 'deleted_at']
47
+ },
48
+ {
49
+ unique: true,
50
+ fields: ['tenant_id', 'user_id', 'deleted_at']
45
51
  }
46
52
  ]
53
+ },
54
+ associate: ({ user, tenantRole, tenantUser, tenantUserRole, tenantOrg, tenantUserOrg }) => {
55
+ tenantUser.belongsToMany(tenantRole, {
56
+ through: tenantUserRole,
57
+ foreignKey: 'tenantUserId',
58
+ otherKey: 'tenantRoleId',
59
+ sourceKey: 'uuid',
60
+ constraints: false
61
+ });
62
+ tenantUser.belongsToMany(tenantOrg, {
63
+ through: tenantUserOrg,
64
+ foreignKey: 'tenantUserId',
65
+ otherKey: 'tenantOrgId',
66
+ sourceKey: 'uuid',
67
+ constraints: false
68
+ });
69
+ tenantUser.belongsTo(user, {
70
+ targetKey: 'uuid',
71
+ constraints: false
72
+ });
47
73
  }
48
- );
49
-
50
- tenantUser.associate = ({ user, tenantRole, tenantUser, tenantUserRole, tenantOrg, tenantUserOrg }) => {
51
- tenantUser.belongsToMany(tenantRole, { through: tenantUserRole });
52
- tenantUser.belongsToMany(tenantOrg, { through: tenantUserOrg });
53
- tenantUser.belongsTo(user);
54
74
  };
55
- return tenantUser;
56
75
  };
@@ -1,12 +1,15 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- return sequelize.define(
3
- 'tenant',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
5
4
  id: {
6
- type: DataTypes.UUID,
7
- defaultValue: DataTypes.UUIDV4,
5
+ type: DataTypes.INTEGER,
6
+ autoIncrement: true,
8
7
  primaryKey: true
9
8
  },
9
+ uuid: {
10
+ type: DataTypes.UUID,
11
+ defaultValue: DataTypes.UUIDV4
12
+ },
10
13
  name: {
11
14
  type: DataTypes.STRING,
12
15
  allowNull: false
@@ -31,8 +34,13 @@ module.exports = (sequelize, DataTypes) => {
31
34
  },
32
35
  description: DataTypes.TEXT
33
36
  },
34
- {
35
- paranoid: true
37
+ options: {
38
+ indexes: [
39
+ {
40
+ unique: true,
41
+ fields: ['uuid', 'deleted_at']
42
+ }
43
+ ]
36
44
  }
37
- );
45
+ };
38
46
  };
@@ -1,12 +1,15 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- return sequelize.define(
3
- 'userAccount',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
5
4
  id: {
6
- type: DataTypes.UUID,
7
- defaultValue: DataTypes.UUIDV4,
5
+ type: DataTypes.INTEGER,
6
+ autoIncrement: true,
8
7
  primaryKey: true
9
8
  },
9
+ uuid: {
10
+ type: DataTypes.UUID,
11
+ defaultValue: DataTypes.UUIDV4
12
+ },
10
13
  password: {
11
14
  type: DataTypes.STRING,
12
15
  allowNull: false
@@ -19,8 +22,13 @@ module.exports = (sequelize, DataTypes) => {
19
22
  type: DataTypes.UUID //用户修改密码时重新生成一条数据,该字段用于记录这个账号之前是属于哪个账号的
20
23
  }
21
24
  },
22
- {
23
- paranoid: true
25
+ options: {
26
+ indexes: [
27
+ {
28
+ unique: true,
29
+ fields: ['uuid', 'deleted_at']
30
+ }
31
+ ]
24
32
  }
25
- );
33
+ };
26
34
  };
@@ -1,12 +1,15 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- const user = sequelize.define(
3
- 'user',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
5
4
  id: {
6
- type: DataTypes.UUID,
7
- defaultValue: DataTypes.UUIDV4,
5
+ type: DataTypes.INTEGER,
6
+ autoIncrement: true,
8
7
  primaryKey: true
9
8
  },
9
+ uuid: {
10
+ type: DataTypes.UUID,
11
+ defaultValue: DataTypes.UUIDV4
12
+ },
10
13
  nickname: DataTypes.STRING,
11
14
  email: DataTypes.STRING,
12
15
  phone: DataTypes.STRING,
@@ -26,25 +29,32 @@ module.exports = (sequelize, DataTypes) => {
26
29
  birthday: DataTypes.DATE,
27
30
  description: DataTypes.TEXT
28
31
  },
29
- {
30
- paranoid: true,
32
+ options: {
31
33
  indexes: [
32
34
  {
33
35
  unique: true,
34
- fields: ['email', 'deletedAt']
36
+ fields: ['uuid', 'deleted_at']
35
37
  },
36
38
  {
37
39
  unique: true,
38
- fields: ['phone', 'deletedAt']
40
+ fields: ['email', 'deleted_at']
41
+ },
42
+ {
43
+ unique: true,
44
+ fields: ['phone', 'deleted_at']
39
45
  }
40
46
  ]
47
+ },
48
+ associate: ({ adminRole, user, tenant, tenantUser }) => {
49
+ user.hasOne(adminRole, { foreignKey: 'userId', sourceKey: 'uuid', constraints: false });
50
+ user.belongsToMany(tenant, {
51
+ through: { model: tenantUser, unique: false },
52
+ otherKey: 'tenantId',
53
+ foreignKey: 'userId',
54
+ targetKey: 'uuid',
55
+ sourceKey: 'uuid',
56
+ constraints: false
57
+ });
41
58
  }
42
- );
43
-
44
- user.associate = ({ adminRole, user, tenant, tenantUser }) => {
45
- user.hasOne(adminRole, { foreignKey: 'userId' });
46
- user.belongsToMany(tenant, { through: { model: tenantUser, unique: false } });
47
59
  };
48
-
49
- return user;
50
60
  };
@@ -1,14 +1,14 @@
1
- module.exports = (sequelize, DataTypes) => {
2
- return sequelize.define(
3
- 'verificationCode',
4
- {
1
+ module.exports = ({ DataTypes }) => {
2
+ return {
3
+ model: {
5
4
  name: {
6
5
  type: DataTypes.STRING,
7
6
  allowNull: false
8
7
  },
9
8
  type: {
10
9
  type: DataTypes.INTEGER,
11
- allowNull: false //0:手机注册,1:邮箱注册,2:手机登录,3:邮箱登录,4:验证租户管理员
10
+ allowNull: false,
11
+ comment: '0:注册,2:登录,4:验证租户管理员,5:忘记密码'
12
12
  },
13
13
  code: {
14
14
  type: DataTypes.STRING,
@@ -16,11 +16,9 @@ module.exports = (sequelize, DataTypes) => {
16
16
  },
17
17
  status: {
18
18
  type: DataTypes.INTEGER,
19
- defaultValue: 0 //0:未验证,1:已验证,2:已过期
19
+ defaultValue: 0,
20
+ comment: '0:未验证,1:已验证,2:已过期'
20
21
  }
21
- },
22
- {
23
- paranoid: true
24
22
  }
25
- );
23
+ };
26
24
  };
@@ -1,6 +1,7 @@
1
1
  const fp = require('fastify-plugin');
2
2
  const dayjs = require('dayjs');
3
3
  const bcrypt = require('bcryptjs');
4
+ const crypto = require('crypto');
4
5
 
5
6
  function generateRandom6DigitNumber() {
6
7
  const randomNumber = Math.random() * 1000000;
@@ -12,9 +13,10 @@ function userNameIsEmail(username) {
12
13
  }
13
14
 
14
15
  module.exports = fp(async (fastify, options) => {
15
- const login = async ({ username, password, ip }) => {
16
+ const { models, services } = fastify.account;
17
+ const login = async ({ username, password, ip, appName }) => {
16
18
  const isEmail = userNameIsEmail(username);
17
- const user = await fastify.account.models.user.findOne({
19
+ const user = await models.user.findOne({
18
20
  where: Object.assign(
19
21
  {},
20
22
  isEmail
@@ -38,16 +40,58 @@ module.exports = fp(async (fastify, options) => {
38
40
 
39
41
  await passwordAuthentication({ accountId: user.userAccountId, password });
40
42
 
41
- await fastify.account.models.loginLog.create({
42
- userId: user.id,
43
- ip
43
+ const application = appName && (await services.application.getApplicationByCode({ code: appName }));
44
+
45
+ await models.loginLog.create({
46
+ userId: user.uuid,
47
+ ip,
48
+ currentTenantId: user.currentTenantId,
49
+ applicationId: application?.id
44
50
  });
45
51
 
46
- return { token: fastify.jwt.sign({ payload: { id: user.id } }), user };
52
+ return {
53
+ token: fastify.jwt.sign({ payload: { id: user.uuid } }),
54
+ user: Object.assign({}, user.get({ plain: true }), { id: user.uuid })
55
+ };
56
+ };
57
+
58
+ const resetPassword = async ({ password, userId }) => {
59
+ const userInfo = await services.user.getUserInstance({ id: userId });
60
+ const account = await models.userAccount.create(
61
+ Object.assign({}, await passwordEncryption(password), {
62
+ belongToUserId: userInfo.uuid
63
+ })
64
+ );
65
+
66
+ await userInfo.update({ userAccountId: account.uuid });
67
+ };
68
+
69
+ const resetPasswordByToken = async ({ password, token }) => {
70
+ const { name } = await verificationJWTCodeValidate({ token });
71
+ const user = await services.user.getUserInstanceByName({ name, status: [0, 1] });
72
+ await resetPassword({ password, userId: user.uuid });
73
+ };
74
+
75
+ const modifyPassword = async ({ email, phone, oldPwd, newPwd }) => {
76
+ const user = await services.user.getUserInstanceByName({ name: email || phone, status: 1 });
77
+ if (!user) {
78
+ throw new Error('新用户密码只能初始化一次');
79
+ }
80
+ if (oldPwd === newPwd) {
81
+ throw new Error('重置密码不能和初始化密码相同');
82
+ }
83
+ await passwordAuthentication({ accountId: user.userAccountId, password: oldPwd });
84
+ await resetPassword({ userId: user.uuid, password: newPwd });
85
+ user.status = 0;
86
+ await user.save();
47
87
  };
48
88
 
49
89
  const passwordAuthentication = async ({ accountId, password }) => {
50
- const userAccount = await fastify.account.models.userAccount.findByPk(accountId);
90
+ const userAccount = await models.userAccount.findOne({
91
+ where: {
92
+ uuid: accountId
93
+ }
94
+ });
51
95
  if (!userAccount) {
52
96
  throw new Error('账号不存在');
53
97
  }
@@ -68,38 +112,19 @@ module.exports = fp(async (fastify, options) => {
68
112
  };
69
113
  };
70
114
 
71
- const resetPassword = async ({ userId, password }) => {
72
- const userInfo = await fastify.account.models.user.findByPk(userId);
73
- if (!userInfo) {
74
- throw new Error('用户不存在');
75
- }
76
- const account = await fastify.account.models.userAccount.create(
77
- Object.assign({}, await passwordEncryption(password), {
78
- belongToUserId: userId
79
- })
80
- );
81
-
82
- await userInfo.update({ userAccountId: account.id });
115
+ const md5 = value => {
116
+ const hash = crypto.createHash('md5');
117
+ hash.update(value);
118
+ return hash.digest('hex');
83
119
  };
84
120
 
85
121
  const register = async ({ avatar, nickname, gender, birthday, description, phone, email, code, password, status, invitationCode }) => {
86
122
  const type = phone ? 0 : 1;
87
- const verificationCode = await fastify.account.models.verificationCode.findOne({
88
- where: {
89
- name: type === 0 ? phone : email,
90
- type,
91
- code,
92
- status: 1
93
- }
94
- });
95
- if (!verificationCode) {
123
+ if (!(await verificationCodeValidate({ name: type === 0 ? phone : email, type: 0, code }))) {
96
124
  throw new Error('验证码不正确或者已经过期');
97
125
  }
98
126
 
99
- verificationCode.status = 2;
100
- await verificationCode.save();
101
-
102
- return await fastify.account.services.user.addUser({
127
+ return await services.user.addUser({
103
128
  avatar,
104
129
  nickname,
105
130
  gender,
@@ -112,35 +137,39 @@ module.exports = fp(async (fastify, options) => {
112
137
  });
113
138
  };
114
139
 
115
- const sendEmailCode = async ({ email }) => {
140
+ const generateVerificationCode = async ({ name, type }) => {
116
141
  const code = generateRandom6DigitNumber();
117
-
118
- // 这里写发送逻辑
119
-
120
- await fastify.account.models.verificationCode.update(
142
+ await models.verificationCode.update(
121
143
  {
122
144
  status: 2
123
145
  },
124
146
  {
125
147
  where: {
126
- name: email,
127
- type: 1,
148
+ name,
149
+ type,
128
150
  status: 0
129
151
  }
130
152
  }
131
153
  );
132
-
133
- await fastify.account.models.verificationCode.create({
134
- name: email,
135
- type: 1,
154
+ await models.verificationCode.create({
155
+ name,
156
+ type,
136
157
  code
137
158
  });
159
+ return code;
160
+ };
138
161
 
162
+ const sendVerificationCode = async ({ name, type }) => {
163
+ // messageType: 0:短信验证码,1:邮件验证码 type: 0:注册,2:登录,4:验证租户管理员,5:忘记密码
164
+ const code = await generateVerificationCode({ name, type });
165
+ const isEmail = userNameIsEmail(name);
166
+ // 这里写发送逻辑
167
+ await options.sendMessage({ name, type, messageType: isEmail ? 1 : 0, props: { code } });
139
168
  return code;
140
169
  };
141
170
 
142
171
  const verificationCodeValidate = async ({ name, type, code }) => {
143
- const verificationCode = await fastify.account.models.verificationCode.findOne({
172
+ const verificationCode = await models.verificationCode.findOne({
144
173
  where: {
145
174
  name,
146
175
  type,
@@ -160,41 +189,36 @@ module.exports = fp(async (fastify, options) => {
160
189
  return isPass;
161
190
  };
162
191
 
163
- const sendSMSCode = async ({ phone }) => {
164
- const code = generateRandom6DigitNumber();
165
-
192
+ const sendJWTVerificationCode = async ({ name, type }) => {
193
+ const code = await generateVerificationCode({ name, type });
194
+ const token = fastify.jwt.sign({ name, type, code });
195
+ const isEmail = userNameIsEmail(name);
166
196
  // 这里写发送逻辑
197
+ await options.sendMessage({ name, type, messageType: isEmail ? 1 : 0, props: { token } });
198
+ return token;
199
+ };
167
200
 
168
- await fastify.account.models.verificationCode.update(
169
- {
170
- status: 2
171
- },
172
- {
173
- where: {
174
- name: phone,
175
- type: 0,
176
- status: 0
177
- }
178
- }
179
- );
180
-
181
- await fastify.account.models.verificationCode.create({
182
- name: phone,
183
- type: 0,
184
- code
185
- });
186
-
187
- return code;
201
+ const verificationJWTCodeValidate = async ({ token }) => {
202
+ const { iat, name, type, code } = fastify.jwt.decode(token);
203
+ if (!(await verificationCodeValidate({ name, type, code }))) {
204
+ throw new Error('验证码不正确或者已经过期');
205
+ }
206
+ return { name, type, code };
188
207
  };
189
208
 
190
- fastify.account.services.account = {
209
+ services.account = {
210
+ md5,
191
211
  login,
212
+ modifyPassword,
192
213
  register,
193
- sendEmailCode,
194
- sendSMSCode,
214
+ generateVerificationCode,
215
+ sendVerificationCode,
195
216
  verificationCodeValidate,
217
+ sendJWTVerificationCode,
218
+ verificationJWTCodeValidate,
196
219
  passwordEncryption,
197
220
  passwordAuthentication,
198
- resetPassword
221
+ resetPassword,
222
+ resetPasswordByToken
199
223
  };
200
224
  });