@kne/fastify-account 1.0.0-alpha.1 → 1.0.0-alpha.2
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 +56 -5
- package/libs/controllers/account.js +2 -2
- package/libs/controllers/tenant.js +12 -1
- package/libs/controllers/user.js +21 -0
- package/libs/models/tenant-role-application.js +5 -1
- package/libs/models/tenant-role-permission.js +7 -1
- package/libs/services/account.js +1 -1
- package/libs/services/tenant.js +160 -3
- package/libs/services/user.js +14 -5
- package/package.json +1 -1
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.
|
|
25
|
+
title: "@kne/fastify-account v1.0.0-alpha.1"
|
|
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.
|
|
45
|
+
<h1 id="-kne-fastify-account">@kne/fastify-account v1.0.0-alpha.1</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
|
|
|
@@ -1938,11 +1938,25 @@ This operation does not require authentication
|
|
|
1938
1938
|
This operation does not require authentication
|
|
1939
1939
|
</aside>
|
|
1940
1940
|
|
|
1941
|
-
##
|
|
1941
|
+
## get__api_v1_account_tenant_getTenantUserInfo
|
|
1942
1942
|
|
|
1943
|
-
`GET /api/v1/account/tenant/
|
|
1943
|
+
`GET /api/v1/account/tenant/getTenantUserInfo`
|
|
1944
1944
|
|
|
1945
|
-
<h3 id="
|
|
1945
|
+
<h3 id="get__api_v1_account_tenant_gettenantuserinfo-responses">Responses</h3>
|
|
1946
|
+
|
|
1947
|
+
|Status|Meaning|Description|Schema|
|
|
1948
|
+
|---|---|---|---|
|
|
1949
|
+
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Default Response|None|
|
|
1950
|
+
|
|
1951
|
+
<aside class="success">
|
|
1952
|
+
This operation does not require authentication
|
|
1953
|
+
</aside>
|
|
1954
|
+
|
|
1955
|
+
## get__api_v1_account_tenant_orgList
|
|
1956
|
+
|
|
1957
|
+
`GET /api/v1/account/tenant/orgList`
|
|
1958
|
+
|
|
1959
|
+
<h3 id="get__api_v1_account_tenant_orglist-responses">Responses</h3>
|
|
1946
1960
|
|
|
1947
1961
|
|Status|Meaning|Description|Schema|
|
|
1948
1962
|
|---|---|---|---|
|
|
@@ -1966,6 +1980,43 @@ This operation does not require authentication
|
|
|
1966
1980
|
This operation does not require authentication
|
|
1967
1981
|
</aside>
|
|
1968
1982
|
|
|
1983
|
+
## post__api_v1_account_setCurrentTenantId
|
|
1984
|
+
|
|
1985
|
+
`POST /api/v1/account/setCurrentTenantId`
|
|
1986
|
+
|
|
1987
|
+
> Body parameter
|
|
1988
|
+
|
|
1989
|
+
```json
|
|
1990
|
+
{
|
|
1991
|
+
"type": "object",
|
|
1992
|
+
"required": [
|
|
1993
|
+
"tenantId"
|
|
1994
|
+
],
|
|
1995
|
+
"properties": {
|
|
1996
|
+
"tenantId": {
|
|
1997
|
+
"type": "string"
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
```
|
|
2002
|
+
|
|
2003
|
+
<h3 id="post__api_v1_account_setcurrenttenantid-parameters">Parameters</h3>
|
|
2004
|
+
|
|
2005
|
+
|Name|In|Type|Required|Description|
|
|
2006
|
+
|---|---|---|---|---|
|
|
2007
|
+
|body|body|object|true|none|
|
|
2008
|
+
|» tenantId|body|string|true|none|
|
|
2009
|
+
|
|
2010
|
+
<h3 id="post__api_v1_account_setcurrenttenantid-responses">Responses</h3>
|
|
2011
|
+
|
|
2012
|
+
|Status|Meaning|Description|Schema|
|
|
2013
|
+
|---|---|---|---|
|
|
2014
|
+
|200|[OK](https://tools.ietf.org/html/rfc7231#section-6.3.1)|Default Response|None|
|
|
2015
|
+
|
|
2016
|
+
<aside class="success">
|
|
2017
|
+
This operation does not require authentication
|
|
2018
|
+
</aside>
|
|
2019
|
+
|
|
1969
2020
|
# Schemas
|
|
1970
2021
|
|
|
1971
2022
|
|
|
@@ -182,8 +182,8 @@ module.exports = fp(async (fastify, options) => {
|
|
|
182
182
|
},
|
|
183
183
|
async request => {
|
|
184
184
|
const { username, password } = request.body;
|
|
185
|
-
const token = await fastify.account.services.account.login({ username, password, ip: request.ip });
|
|
186
|
-
return { token };
|
|
185
|
+
const { token, user } = await fastify.account.services.account.login({ username, password, ip: request.ip });
|
|
186
|
+
return { token, currentTenantId: user.currentTenantId };
|
|
187
187
|
}
|
|
188
188
|
);
|
|
189
189
|
});
|
|
@@ -11,7 +11,7 @@ module.exports = fp(async (fastify, options) => {
|
|
|
11
11
|
);
|
|
12
12
|
|
|
13
13
|
fastify.get(
|
|
14
|
-
`${options.prefix}/tenant/
|
|
14
|
+
`${options.prefix}/tenant/getTenantUserInfo`,
|
|
15
15
|
{
|
|
16
16
|
onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.tenant]
|
|
17
17
|
},
|
|
@@ -19,4 +19,15 @@ module.exports = fp(async (fastify, options) => {
|
|
|
19
19
|
return request.tenantInfo;
|
|
20
20
|
}
|
|
21
21
|
);
|
|
22
|
+
|
|
23
|
+
fastify.get(
|
|
24
|
+
`${options.prefix}/tenant/orgList`,
|
|
25
|
+
{
|
|
26
|
+
onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.tenant]
|
|
27
|
+
},
|
|
28
|
+
async request => {
|
|
29
|
+
const { tenantId } = request.tenantInfo;
|
|
30
|
+
return await fastify.account.services.tenant.getTenantOrgList({ tenantId });
|
|
31
|
+
}
|
|
32
|
+
);
|
|
22
33
|
});
|
package/libs/controllers/user.js
CHANGED
|
@@ -9,4 +9,25 @@ module.exports = fp(async (fastify, options) => {
|
|
|
9
9
|
return { userInfo: request.userInfo };
|
|
10
10
|
}
|
|
11
11
|
);
|
|
12
|
+
|
|
13
|
+
fastify.post(
|
|
14
|
+
`${options.prefix}/setCurrentTenantId`,
|
|
15
|
+
{
|
|
16
|
+
onRequest: [fastify.account.authenticate.user],
|
|
17
|
+
schema: {
|
|
18
|
+
body: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
required: ['tenantId'],
|
|
21
|
+
properties: {
|
|
22
|
+
tenantId: { type: 'string' }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
async request => {
|
|
28
|
+
const { tenantId } = request.body;
|
|
29
|
+
await fastify.account.services.user.setCurrentTenantId({ id: request.userInfo.id, tenantId });
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
);
|
|
12
33
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
|
|
2
|
+
const tenantRoleApplication = sequelize.define(
|
|
3
3
|
'tenantRoleApplication',
|
|
4
4
|
{
|
|
5
5
|
tenantId: {
|
|
@@ -30,4 +30,8 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
30
30
|
]
|
|
31
31
|
}
|
|
32
32
|
);
|
|
33
|
+
tenantRoleApplication.associate = ({ tenantRoleApplication, application }) => {
|
|
34
|
+
tenantRoleApplication.belongsTo(application);
|
|
35
|
+
};
|
|
36
|
+
return tenantRoleApplication;
|
|
33
37
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
|
|
2
|
+
const tenantRolePermission = sequelize.define(
|
|
3
3
|
'tenantRolePermission',
|
|
4
4
|
{
|
|
5
5
|
tenantId: {
|
|
@@ -30,4 +30,10 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
30
30
|
]
|
|
31
31
|
}
|
|
32
32
|
);
|
|
33
|
+
|
|
34
|
+
tenantRolePermission.associate = ({ tenantRolePermission, permission }) => {
|
|
35
|
+
tenantRolePermission.belongsTo(permission);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return tenantRolePermission;
|
|
33
39
|
};
|
package/libs/services/account.js
CHANGED
|
@@ -43,7 +43,7 @@ module.exports = fp(async (fastify, options) => {
|
|
|
43
43
|
ip
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
return fastify.jwt.sign({ payload: { id: user.id } });
|
|
46
|
+
return { token: fastify.jwt.sign({ payload: { id: user.id } }), user };
|
|
47
47
|
};
|
|
48
48
|
|
|
49
49
|
const passwordAuthentication = async ({ accountId, password }) => {
|
package/libs/services/tenant.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const fp = require('fastify-plugin');
|
|
2
2
|
const isNil = require('lodash/isNil');
|
|
3
|
+
const { Unauthorized } = require('http-errors');
|
|
4
|
+
const transform = require('lodash/transform');
|
|
5
|
+
const groupBy = require('lodash/groupBy');
|
|
6
|
+
const pick = require('lodash/pick');
|
|
3
7
|
module.exports = fp(async (fastify, options) => {
|
|
4
8
|
const getUserTenant = async authenticatePayload => {
|
|
5
9
|
const user = await fastify.account.services.user.getUserInfo(authenticatePayload);
|
|
@@ -115,9 +119,129 @@ module.exports = fp(async (fastify, options) => {
|
|
|
115
119
|
await tenantRole.destroy();
|
|
116
120
|
};
|
|
117
121
|
|
|
122
|
+
const getTenantUserPermissionList = async ({ tenantRoleIds }) => {
|
|
123
|
+
const tenantRoleApplication = await fastify.account.models.tenantRoleApplication.findAll({
|
|
124
|
+
attributes: ['applicationId'],
|
|
125
|
+
where: {
|
|
126
|
+
roleId: {
|
|
127
|
+
[fastify.sequelize.Sequelize.Op.in]: tenantRoleIds
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const applications = await fastify.account.models.application.findAll({
|
|
133
|
+
attributes: ['id', 'code', 'name'],
|
|
134
|
+
where: {
|
|
135
|
+
id: {
|
|
136
|
+
[fastify.sequelize.Sequelize.Op.in]: tenantRoleApplication.map(({ applicationId }) => applicationId)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const tenantRolePermission = await fastify.account.models.tenantRolePermission.findAll({
|
|
142
|
+
attributes: ['permissionId'],
|
|
143
|
+
include: {
|
|
144
|
+
attributes: ['code', 'name', 'isModule', 'paths'],
|
|
145
|
+
model: fastify.account.models.permission
|
|
146
|
+
},
|
|
147
|
+
where: {
|
|
148
|
+
roleId: {
|
|
149
|
+
[fastify.sequelize.Sequelize.Op.in]: tenantRoleIds
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const permissions = await fastify.account.models.permission.findAll({
|
|
155
|
+
attributes: ['id', 'code', 'name', 'isModule', 'pid', 'applicationId', 'paths'],
|
|
156
|
+
where: {
|
|
157
|
+
[fastify.sequelize.Sequelize.Op.or]: [
|
|
158
|
+
{
|
|
159
|
+
id: {
|
|
160
|
+
[fastify.sequelize.Sequelize.Op.in]: tenantRolePermission.map(({ permissionId }) => permissionId)
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
isMust: true
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const permissionMapping = transform(
|
|
171
|
+
await fastify.account.models.permission.findAll({
|
|
172
|
+
where: {
|
|
173
|
+
id: {
|
|
174
|
+
[fastify.sequelize.Sequelize.Op.in]: permissions.map(({ paths }) => paths).reduce((list, item) => [...list, ...(item || [])], [])
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}),
|
|
178
|
+
(result, value) => {
|
|
179
|
+
result[value.id] = { code: value.code, name: value.name };
|
|
180
|
+
},
|
|
181
|
+
{}
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const applicationsMapping = transform(
|
|
185
|
+
applications,
|
|
186
|
+
(result, value) => {
|
|
187
|
+
result[value.id] = value;
|
|
188
|
+
},
|
|
189
|
+
{}
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const findEndChildren = permissions => {
|
|
193
|
+
const output = [];
|
|
194
|
+
const core = (list, node) => {
|
|
195
|
+
const { children, other } = groupBy(list, item => (item.pid === node.id ? 'children' : 'other'));
|
|
196
|
+
if (!(other && other.length > 0)) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!(children && children.length > 0)) {
|
|
200
|
+
node.id !== 0 && output.push(node);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
children.forEach(node => {
|
|
205
|
+
core(other, node);
|
|
206
|
+
});
|
|
207
|
+
return output;
|
|
208
|
+
};
|
|
209
|
+
core(permissions, { id: 0 });
|
|
210
|
+
return output;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const userPermissionList = findEndChildren(permissions).map(({ code, applicationId, paths }) => {
|
|
214
|
+
return `${applicationsMapping[applicationId].code}${
|
|
215
|
+
paths && paths.length > 0
|
|
216
|
+
? `:${paths
|
|
217
|
+
.map(id => {
|
|
218
|
+
return permissionMapping[id].code;
|
|
219
|
+
})
|
|
220
|
+
.join(':')}`
|
|
221
|
+
: ''
|
|
222
|
+
}:${code}`;
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
applications: applications,
|
|
227
|
+
permissions: permissions.map(item =>
|
|
228
|
+
Object.assign(
|
|
229
|
+
{},
|
|
230
|
+
{
|
|
231
|
+
code: item.code,
|
|
232
|
+
name: item.name,
|
|
233
|
+
isModule: item.isModule,
|
|
234
|
+
paths: (item.paths || []).map(id => permissionMapping[id])
|
|
235
|
+
}
|
|
236
|
+
)
|
|
237
|
+
),
|
|
238
|
+
userPermissionList
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
|
|
118
242
|
const tenantUserAuthenticate = async user => {
|
|
119
243
|
if (!user.currentTenantId) {
|
|
120
|
-
throw new
|
|
244
|
+
throw new Unauthorized('没有找到当前绑定租户');
|
|
121
245
|
}
|
|
122
246
|
const tenant = await fastify.account.models.tenant.findByPk(user.currentTenantId, {
|
|
123
247
|
where: {
|
|
@@ -129,6 +253,17 @@ module.exports = fp(async (fastify, options) => {
|
|
|
129
253
|
}
|
|
130
254
|
|
|
131
255
|
const tenantUser = await fastify.account.models.tenantUser.findOne({
|
|
256
|
+
attributes: ['id', 'avatar', 'description', 'phone', 'email'],
|
|
257
|
+
include: [
|
|
258
|
+
{
|
|
259
|
+
attributes: ['id', 'name'],
|
|
260
|
+
model: fastify.account.models.tenantOrg
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
attributes: ['id', 'name'],
|
|
264
|
+
model: fastify.account.models.tenantRole
|
|
265
|
+
}
|
|
266
|
+
],
|
|
132
267
|
where: {
|
|
133
268
|
tenantId: tenant.id,
|
|
134
269
|
userId: user.id,
|
|
@@ -136,13 +271,35 @@ module.exports = fp(async (fastify, options) => {
|
|
|
136
271
|
}
|
|
137
272
|
});
|
|
138
273
|
|
|
274
|
+
// 获取当前租户默认角色
|
|
275
|
+
const defaultTenant = await fastify.account.models.tenantRole.findOne({
|
|
276
|
+
where: {
|
|
277
|
+
type: 1,
|
|
278
|
+
tenantId: tenant.id
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
if (!defaultTenant) {
|
|
283
|
+
throw new Error('租户默认角色未设置,请联系管理员');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const tenantRoleIds = tenantUser.tenantRoles.map(({ id }) => id);
|
|
287
|
+
tenantRoleIds.push(defaultTenant.id);
|
|
288
|
+
|
|
289
|
+
const { userPermissionList } = await getTenantUserPermissionList({ tenantRoleIds });
|
|
139
290
|
if (!tenantUser) {
|
|
140
291
|
throw new Error('当前租户用户不存在或者已经被关闭');
|
|
141
292
|
}
|
|
142
293
|
|
|
294
|
+
const outputTenantUser = Object.assign({}, tenantUser.get({ plain: true }));
|
|
295
|
+
outputTenantUser.tenantOrgs = outputTenantUser?.tenantOrgs.map(({ id, name }) => ({ id, name }));
|
|
296
|
+
outputTenantUser.tenantRoles = outputTenantUser?.tenantRoles.map(({ id, name }) => ({ id, name }));
|
|
143
297
|
return {
|
|
144
|
-
tenant,
|
|
145
|
-
tenantUser
|
|
298
|
+
tenant: pick(tenant, ['id', 'name', 'description']),
|
|
299
|
+
tenantUser: Object.assign({}, outputTenantUser, {
|
|
300
|
+
permissions: userPermissionList
|
|
301
|
+
}),
|
|
302
|
+
user
|
|
146
303
|
};
|
|
147
304
|
};
|
|
148
305
|
|
package/libs/services/user.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fp = require('fastify-plugin');
|
|
2
2
|
const { Unauthorized } = require('http-errors');
|
|
3
3
|
const get = require('lodash/get');
|
|
4
|
+
const pick = require('lodash/pick');
|
|
4
5
|
module.exports = fp(async (fastify, options) => {
|
|
5
6
|
const getUserInfo = async authenticatePayload => {
|
|
6
7
|
if (!(authenticatePayload && authenticatePayload.id)) {
|
|
@@ -10,10 +11,7 @@ module.exports = fp(async (fastify, options) => {
|
|
|
10
11
|
if (!user) {
|
|
11
12
|
throw new Unauthorized();
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
delete userInfo['userAccountId'];
|
|
15
|
-
|
|
16
|
-
return userInfo;
|
|
14
|
+
return pick(user, ['id', 'avatar', 'nickname', 'phone', 'email', 'gender', 'status', 'birthday', 'description', 'currentTenantId']);
|
|
17
15
|
};
|
|
18
16
|
|
|
19
17
|
const accountIsExists = async ({ email, phone }, currentUser) => {
|
|
@@ -97,12 +95,23 @@ module.exports = fp(async (fastify, options) => {
|
|
|
97
95
|
await user.save();
|
|
98
96
|
};
|
|
99
97
|
|
|
98
|
+
const setCurrentTenantId = async ({ id, tenantId }) => {
|
|
99
|
+
await fastify.account.services.tenant.getTenantInfo({ id: tenantId });
|
|
100
|
+
const user = await fastify.account.models.user.findByPk(id);
|
|
101
|
+
|
|
102
|
+
if (!user) {
|
|
103
|
+
throw new Error('用户不存在');
|
|
104
|
+
}
|
|
105
|
+
user.currentTenantId = tenantId;
|
|
106
|
+
await user.save();
|
|
107
|
+
};
|
|
100
108
|
fastify.account.services.user = {
|
|
101
109
|
getUserInfo,
|
|
102
110
|
saveUser,
|
|
103
111
|
accountIsExists,
|
|
104
112
|
addUser,
|
|
105
113
|
closeUser,
|
|
106
|
-
openUser
|
|
114
|
+
openUser,
|
|
115
|
+
setCurrentTenantId
|
|
107
116
|
};
|
|
108
117
|
});
|