@kne/fastify-signature 1.0.3 → 1.0.4

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.
@@ -1,4 +1,8 @@
1
1
  const fp = require('fastify-plugin');
2
+ const { str, bool, any, success, empty, pageResult, STATUS, secret } = require('../schema/response');
3
+
4
+ const ADMIN_TAG = '签名管理后台-密钥';
5
+ const TAG = '签名-验签';
2
6
 
3
7
  module.exports = fp(async (fastify, options) => {
4
8
  const { services } = fastify[options.name];
@@ -9,7 +13,8 @@ module.exports = fp(async (fastify, options) => {
9
13
  {
10
14
  onRequest: [userAuth, adminAuth],
11
15
  schema: {
12
- description: '获取密钥列表',
16
+ tags: [ADMIN_TAG],
17
+ description: '分页查询全部用户的密钥,按创建时间倒序;密钥只返回脱敏值',
13
18
  summary: '获取密钥列表',
14
19
  query: {
15
20
  type: 'object',
@@ -27,6 +32,7 @@ module.exports = fp(async (fastify, options) => {
27
32
  filter: {
28
33
  type: 'object',
29
34
  additionalProperties: true,
35
+ description: '筛选条件',
30
36
  properties: {
31
37
  keyword: { type: 'string', description: '关键字(AppId/描述/所属用户)' },
32
38
  appId: { type: 'string', description: 'AppId' },
@@ -34,7 +40,8 @@ module.exports = fp(async (fastify, options) => {
34
40
  }
35
41
  }
36
42
  }
37
- }
43
+ },
44
+ response: success('密钥分页列表', pageResult('密钥', secret))
38
45
  }
39
46
  },
40
47
  async request => {
@@ -47,7 +54,8 @@ module.exports = fp(async (fastify, options) => {
47
54
  {
48
55
  onRequest: [userAuth, adminAuth],
49
56
  schema: {
50
- description: '创建密钥',
57
+ tags: [ADMIN_TAG],
58
+ description: '生成一对 AppId / 密钥,密钥明文只在创建时返回一次',
51
59
  summary: '创建密钥',
52
60
  body: {
53
61
  type: 'object',
@@ -55,9 +63,19 @@ module.exports = fp(async (fastify, options) => {
55
63
  description: {
56
64
  type: 'string',
57
65
  description: '描述'
66
+ },
67
+ userId: {
68
+ description: '密钥所属用户 ID,不传为当前登录用户;验签通过后以该用户身份访问开放接口'
58
69
  }
59
70
  }
60
- }
71
+ },
72
+ response: success('创建的密钥', {
73
+ type: 'object',
74
+ properties: {
75
+ appId: str('AppId'),
76
+ secretKey: str('密钥明文,只返回这一次')
77
+ }
78
+ })
61
79
  }
62
80
  },
63
81
  async request => {
@@ -70,7 +88,8 @@ module.exports = fp(async (fastify, options) => {
70
88
  {
71
89
  onRequest: [userAuth, adminAuth],
72
90
  schema: {
73
- description: '删除密钥',
91
+ tags: [ADMIN_TAG],
92
+ description: '删除密钥,删除后该 AppId 无法再通过验签;AppId 不存在时报错',
74
93
  summary: '删除密钥',
75
94
  body: {
76
95
  type: 'object',
@@ -80,7 +99,8 @@ module.exports = fp(async (fastify, options) => {
80
99
  description: '密钥ID'
81
100
  }
82
101
  }
83
- }
102
+ },
103
+ response: empty('删除成功')
84
104
  }
85
105
  },
86
106
  async request => {
@@ -94,7 +114,8 @@ module.exports = fp(async (fastify, options) => {
94
114
  {
95
115
  onRequest: [userAuth, adminAuth],
96
116
  schema: {
97
- description: '更新密钥',
117
+ tags: [ADMIN_TAG],
118
+ description: '修改密钥状态与描述,未传的字段保持原值;AppId 不存在时报错',
98
119
  summary: '更新密钥',
99
120
  body: {
100
121
  type: 'object',
@@ -105,14 +126,15 @@ module.exports = fp(async (fastify, options) => {
105
126
  },
106
127
  status: {
107
128
  type: 'number',
108
- description: '密钥状态'
129
+ description: `密钥${STATUS}`
109
130
  },
110
131
  description: {
111
132
  type: 'string',
112
133
  description: '描述'
113
134
  }
114
135
  }
115
- }
136
+ },
137
+ response: empty('更新成功')
116
138
  }
117
139
  },
118
140
  async request => {
@@ -125,7 +147,8 @@ module.exports = fp(async (fastify, options) => {
125
147
  `${options.prefix}/verify`,
126
148
  {
127
149
  schema: {
128
- description: '验证密钥',
150
+ tags: [TAG],
151
+ description: '免登录。按 HMAC-SHA256(`${appId}|${timestamp}|${expire}`, 密钥) 校验签名,通过后记录最后访问时间;签名错误或过期返回 result=false,AppId 不存在时报错',
129
152
  summary: '验证密钥',
130
153
  body: {
131
154
  type: 'object',
@@ -136,18 +159,26 @@ module.exports = fp(async (fastify, options) => {
136
159
  },
137
160
  timestamp: {
138
161
  type: 'number',
139
- description: '时间戳'
162
+ description: '签名时的时间戳(秒)'
140
163
  },
141
164
  signature: {
142
165
  type: 'string',
143
- description: '签名'
166
+ description: '签名(hex)'
144
167
  },
145
168
  expire: {
146
169
  type: 'number',
147
- description: '过期时间'
170
+ description: '过期时间戳(秒),当前时间超过即验签失败'
148
171
  }
149
172
  }
150
- }
173
+ },
174
+ response: success('验签结果', {
175
+ type: 'object',
176
+ properties: {
177
+ result: bool('是否通过验签'),
178
+ message: str('结果说明'),
179
+ userId: any('密钥所属用户 ID,仅通过验签时返回')
180
+ }
181
+ })
151
182
  }
152
183
  },
153
184
  async request => {
@@ -0,0 +1,39 @@
1
+ // 响应 schema 会参与 fast-json-stringify 序列化:对象一律 additionalProperties: true 以免裁掉未声明字段;
2
+ // 用 nullable 而非类型数组(类型数组遇到不匹配的值会直接 500),类型不确定的字段(如外键 id、日期)只写说明不声明类型
3
+ const str = description => ({ type: 'string', nullable: true, description });
4
+ const num = description => ({ type: 'number', nullable: true, description });
5
+ const bool = description => ({ type: 'boolean', nullable: true, description });
6
+ const any = description => ({ description });
7
+ const list = (description, items) => ({ type: 'array', nullable: true, description, items });
8
+ const obj = (description, properties = {}) => ({ type: 'object', nullable: true, description, additionalProperties: true, properties });
9
+
10
+ const success = (description, schema) => ({
11
+ 200: Object.assign({}, schema || { type: 'object' }, { description })
12
+ });
13
+
14
+ const empty = (description = '操作成功,返回空对象') => success(description);
15
+
16
+ const pageResult = (description, item) => ({
17
+ type: 'object',
18
+ additionalProperties: true,
19
+ properties: {
20
+ pageData: list(`当前页${description}列表`, item),
21
+ totalCount: num('符合条件的总条数')
22
+ }
23
+ });
24
+
25
+ const STATUS = '状态:0 开启,1 禁用';
26
+
27
+ const secret = obj('密钥', {
28
+ id: str('密钥 ID(同 appId)'),
29
+ appId: str('AppId,即密钥 ID'),
30
+ secretKey: str('脱敏后的密钥,只保留首尾各 3 位'),
31
+ user: any('所属用户,未关联到用户时为 null'),
32
+ description: str('描述'),
33
+ lastVisitedAt: any('最后一次验签成功的时间'),
34
+ status: num(STATUS),
35
+ createdAt: any('创建时间'),
36
+ updatedAt: any('更新时间')
37
+ });
38
+
39
+ module.exports = { str, num, bool, any, list, obj, success, empty, pageResult, STATUS, secret };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kne/fastify-signature",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "用于实现一个签名和验证算法",
5
5
  "main": "index.js",
6
6
  "scripts": {