befly 3.9.38 → 3.9.40
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 +37 -38
- package/befly.config.ts +62 -40
- package/checks/checkApi.ts +16 -16
- package/checks/checkApp.ts +19 -25
- package/checks/checkTable.ts +42 -42
- package/docs/README.md +42 -35
- package/docs/{api.md → api/api.md} +223 -231
- package/docs/cipher.md +71 -69
- package/docs/database.md +143 -141
- package/docs/{examples.md → guide/examples.md} +181 -181
- package/docs/guide/quickstart.md +331 -0
- package/docs/hooks/auth.md +38 -0
- package/docs/hooks/cors.md +28 -0
- package/docs/{hook.md → hooks/hook.md} +140 -57
- package/docs/hooks/parser.md +19 -0
- package/docs/hooks/rateLimit.md +47 -0
- package/docs/{redis.md → infra/redis.md} +84 -93
- package/docs/plugins/cipher.md +61 -0
- package/docs/plugins/database.md +128 -0
- package/docs/{plugin.md → plugins/plugin.md} +83 -81
- package/docs/quickstart.md +26 -26
- package/docs/{addon.md → reference/addon.md} +46 -46
- package/docs/{config.md → reference/config.md} +32 -80
- package/docs/{logger.md → reference/logger.md} +52 -52
- package/docs/{sync.md → reference/sync.md} +32 -35
- package/docs/{table.md → reference/table.md} +1 -1
- package/docs/{validator.md → reference/validator.md} +57 -57
- package/hooks/auth.ts +8 -4
- package/hooks/cors.ts +13 -13
- package/hooks/parser.ts +37 -17
- package/hooks/permission.ts +26 -14
- package/hooks/rateLimit.ts +276 -0
- package/hooks/validator.ts +8 -8
- package/lib/asyncContext.ts +43 -0
- package/lib/cacheHelper.ts +212 -77
- package/lib/cacheKeys.ts +38 -0
- package/lib/cipher.ts +30 -30
- package/lib/connect.ts +28 -28
- package/lib/dbHelper.ts +183 -102
- package/lib/jwt.ts +16 -16
- package/lib/logger.ts +610 -19
- package/lib/redisHelper.ts +185 -44
- package/lib/sqlBuilder.ts +90 -91
- package/lib/validator.ts +59 -39
- package/loader/loadApis.ts +48 -44
- package/loader/loadHooks.ts +40 -14
- package/loader/loadPlugins.ts +16 -17
- package/main.ts +57 -47
- package/package.json +47 -45
- package/paths.ts +15 -14
- package/plugins/cache.ts +5 -4
- package/plugins/cipher.ts +3 -3
- package/plugins/config.ts +2 -2
- package/plugins/db.ts +9 -9
- package/plugins/jwt.ts +3 -3
- package/plugins/logger.ts +8 -12
- package/plugins/redis.ts +8 -8
- package/plugins/tool.ts +6 -6
- package/router/api.ts +85 -56
- package/router/static.ts +12 -12
- package/sync/syncAll.ts +12 -12
- package/sync/syncApi.ts +55 -52
- package/sync/syncDb/apply.ts +20 -19
- package/sync/syncDb/constants.ts +25 -23
- package/sync/syncDb/ddl.ts +35 -36
- package/sync/syncDb/helpers.ts +6 -9
- package/sync/syncDb/schema.ts +10 -9
- package/sync/syncDb/sqlite.ts +7 -8
- package/sync/syncDb/table.ts +37 -35
- package/sync/syncDb/tableCreate.ts +21 -20
- package/sync/syncDb/types.ts +23 -20
- package/sync/syncDb/version.ts +10 -10
- package/sync/syncDb.ts +43 -36
- package/sync/syncDev.ts +74 -65
- package/sync/syncMenu.ts +190 -55
- package/tests/api-integration-array-number.test.ts +282 -0
- package/tests/befly-config-env.test.ts +78 -0
- package/tests/cacheHelper.test.ts +135 -104
- package/tests/cacheKeys.test.ts +41 -0
- package/tests/cipher.test.ts +90 -89
- package/tests/dbHelper-advanced.test.ts +140 -134
- package/tests/dbHelper-all-array-types.test.ts +316 -0
- package/tests/dbHelper-array-serialization.test.ts +258 -0
- package/tests/dbHelper-columns.test.ts +56 -55
- package/tests/dbHelper-execute.test.ts +45 -44
- package/tests/dbHelper-joins.test.ts +124 -119
- package/tests/fields-redis-cache.test.ts +29 -27
- package/tests/fields-validate.test.ts +38 -38
- package/tests/getClientIp.test.ts +54 -0
- package/tests/integration.test.ts +69 -67
- package/tests/jwt.test.ts +27 -26
- package/tests/logger.test.ts +267 -34
- package/tests/rateLimit-hook.test.ts +477 -0
- package/tests/redisHelper.test.ts +187 -188
- package/tests/redisKeys.test.ts +6 -73
- package/tests/scanConfig.test.ts +144 -0
- package/tests/sqlBuilder-advanced.test.ts +217 -215
- package/tests/sqlBuilder.test.ts +92 -91
- package/tests/sync-connection.test.ts +29 -29
- package/tests/syncDb-apply.test.ts +97 -96
- package/tests/syncDb-array-number.test.ts +160 -0
- package/tests/syncDb-constants.test.ts +48 -47
- package/tests/syncDb-ddl.test.ts +99 -98
- package/tests/syncDb-helpers.test.ts +29 -28
- package/tests/syncDb-schema.test.ts +61 -60
- package/tests/syncDb-types.test.ts +60 -59
- package/tests/syncMenu-paths.test.ts +68 -0
- package/tests/util.test.ts +42 -41
- package/tests/validator-array-number.test.ts +310 -0
- package/tests/validator-default.test.ts +373 -0
- package/tests/validator.test.ts +271 -266
- package/tsconfig.json +4 -5
- package/types/api.d.ts +7 -12
- package/types/befly.d.ts +60 -13
- package/types/cache.d.ts +8 -4
- package/types/common.d.ts +17 -9
- package/types/context.d.ts +2 -2
- package/types/crypto.d.ts +23 -0
- package/types/database.d.ts +19 -19
- package/types/hook.d.ts +2 -2
- package/types/jwt.d.ts +118 -0
- package/types/logger.d.ts +30 -0
- package/types/plugin.d.ts +4 -4
- package/types/redis.d.ts +7 -3
- package/types/roleApisCache.ts +23 -0
- package/types/sync.d.ts +10 -10
- package/types/table.d.ts +50 -9
- package/types/validate.d.ts +69 -0
- package/utils/addonHelper.ts +90 -0
- package/utils/arrayKeysToCamel.ts +18 -0
- package/utils/calcPerfTime.ts +13 -0
- package/utils/configTypes.ts +3 -0
- package/utils/cors.ts +19 -0
- package/utils/fieldClear.ts +75 -0
- package/utils/genShortId.ts +12 -0
- package/utils/getClientIp.ts +45 -0
- package/utils/keysToCamel.ts +22 -0
- package/utils/keysToSnake.ts +22 -0
- package/utils/modules.ts +98 -0
- package/utils/pickFields.ts +19 -0
- package/utils/process.ts +56 -0
- package/utils/regex.ts +225 -0
- package/utils/response.ts +115 -0
- package/utils/route.ts +23 -0
- package/utils/scanConfig.ts +142 -0
- package/utils/scanFiles.ts +48 -0
- package/.prettierignore +0 -2
- package/.prettierrc +0 -12
- package/docs/1-/345/237/272/346/234/254/344/273/213/347/273/215.md +0 -35
- package/docs/2-/345/210/235/346/255/245/344/275/223/351/252/214.md +0 -64
- package/docs/3-/347/254/254/344/270/200/344/270/252/346/216/245/345/217/243.md +0 -46
- package/docs/4-/346/223/215/344/275/234/346/225/260/346/215/256/345/272/223.md +0 -172
- package/hooks/requestLogger.ts +0 -84
- package/types/index.ts +0 -24
- package/util.ts +0 -283
package/docs/cipher.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> 哈希、签名、密码加密与 JWT 令牌
|
|
4
4
|
|
|
5
|
+
> 本文档已迁移到:[`./plugins/cipher.md`](./plugins/cipher.md)
|
|
6
|
+
|
|
5
7
|
## 目录
|
|
6
8
|
|
|
7
9
|
- [概述](#概述)
|
|
@@ -37,7 +39,7 @@ Befly 提供两个安全相关的工具:
|
|
|
37
39
|
### 基本导入
|
|
38
40
|
|
|
39
41
|
```typescript
|
|
40
|
-
import { Cipher } from
|
|
42
|
+
import { Cipher } from "../lib/cipher.js";
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
### 哈希算法
|
|
@@ -46,31 +48,31 @@ import { Cipher } from '../lib/cipher.js';
|
|
|
46
48
|
|
|
47
49
|
```typescript
|
|
48
50
|
// 基本用法
|
|
49
|
-
const hash = Cipher.md5(
|
|
51
|
+
const hash = Cipher.md5("hello");
|
|
50
52
|
// '5d41402abc4b2a76b9719d911017c592'
|
|
51
53
|
|
|
52
54
|
// 指定编码
|
|
53
|
-
const hashBase64 = Cipher.md5(
|
|
55
|
+
const hashBase64 = Cipher.md5("hello", "base64");
|
|
54
56
|
```
|
|
55
57
|
|
|
56
58
|
#### SHA-1
|
|
57
59
|
|
|
58
60
|
```typescript
|
|
59
|
-
const hash = Cipher.sha1(
|
|
61
|
+
const hash = Cipher.sha1("hello");
|
|
60
62
|
// 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
|
|
61
63
|
```
|
|
62
64
|
|
|
63
65
|
#### SHA-256
|
|
64
66
|
|
|
65
67
|
```typescript
|
|
66
|
-
const hash = Cipher.sha256(
|
|
68
|
+
const hash = Cipher.sha256("hello");
|
|
67
69
|
// '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
|
|
68
70
|
```
|
|
69
71
|
|
|
70
72
|
#### SHA-512
|
|
71
73
|
|
|
72
74
|
```typescript
|
|
73
|
-
const hash = Cipher.sha512(
|
|
75
|
+
const hash = Cipher.sha512("hello");
|
|
74
76
|
// '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca...'
|
|
75
77
|
```
|
|
76
78
|
|
|
@@ -78,9 +80,9 @@ const hash = Cipher.sha512('hello');
|
|
|
78
80
|
|
|
79
81
|
```typescript
|
|
80
82
|
// 支持多种算法
|
|
81
|
-
const hash = Cipher.hash(
|
|
82
|
-
const hash2 = Cipher.hash(
|
|
83
|
-
const hash3 = Cipher.hash(
|
|
83
|
+
const hash = Cipher.hash("sha256", "hello");
|
|
84
|
+
const hash2 = Cipher.hash("sha384", "hello");
|
|
85
|
+
const hash3 = Cipher.hash("blake2b256", "hello");
|
|
84
86
|
```
|
|
85
87
|
|
|
86
88
|
#### 支持的算法
|
|
@@ -108,22 +110,22 @@ const hash3 = Cipher.hash('blake2b256', 'hello');
|
|
|
108
110
|
HMAC 使用密钥进行签名,用于数据完整性验证:
|
|
109
111
|
|
|
110
112
|
```typescript
|
|
111
|
-
const key =
|
|
113
|
+
const key = "my-secret-key";
|
|
112
114
|
|
|
113
115
|
// HMAC-MD5
|
|
114
|
-
const sig1 = Cipher.hmacMd5(key,
|
|
116
|
+
const sig1 = Cipher.hmacMd5(key, "data");
|
|
115
117
|
|
|
116
118
|
// HMAC-SHA1
|
|
117
|
-
const sig2 = Cipher.hmacSha1(key,
|
|
119
|
+
const sig2 = Cipher.hmacSha1(key, "data");
|
|
118
120
|
|
|
119
121
|
// HMAC-SHA256(推荐)
|
|
120
|
-
const sig3 = Cipher.hmacSha256(key,
|
|
122
|
+
const sig3 = Cipher.hmacSha256(key, "data");
|
|
121
123
|
|
|
122
124
|
// HMAC-SHA512
|
|
123
|
-
const sig4 = Cipher.hmacSha512(key,
|
|
125
|
+
const sig4 = Cipher.hmacSha512(key, "data");
|
|
124
126
|
|
|
125
127
|
// 通用 HMAC
|
|
126
|
-
const sig5 = Cipher.hmac(
|
|
128
|
+
const sig5 = Cipher.hmac("sha256", key, "data");
|
|
127
129
|
```
|
|
128
130
|
|
|
129
131
|
#### RSA-SHA256 签名
|
|
@@ -135,9 +137,9 @@ const privateKey = `-----BEGIN PRIVATE KEY-----
|
|
|
135
137
|
MIIEvQIBADANBg...
|
|
136
138
|
-----END PRIVATE KEY-----`;
|
|
137
139
|
|
|
138
|
-
const signature = Cipher.rsaSha256(
|
|
140
|
+
const signature = Cipher.rsaSha256("data to sign", privateKey);
|
|
139
141
|
// 或指定编码
|
|
140
|
-
const signatureBase64 = Cipher.rsaSha256(
|
|
142
|
+
const signatureBase64 = Cipher.rsaSha256("data to sign", privateKey, "base64");
|
|
141
143
|
```
|
|
142
144
|
|
|
143
145
|
### 密码加密
|
|
@@ -148,17 +150,17 @@ const signatureBase64 = Cipher.rsaSha256('data to sign', privateKey, 'base64');
|
|
|
148
150
|
|
|
149
151
|
```typescript
|
|
150
152
|
// 默认配置(推荐)
|
|
151
|
-
const hash = await Cipher.hashPassword(
|
|
153
|
+
const hash = await Cipher.hashPassword("123456");
|
|
152
154
|
// '$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92...'
|
|
153
155
|
|
|
154
156
|
// 自定义强度(cost 越高越安全但越慢)
|
|
155
|
-
const hash2 = await Cipher.hashPassword(
|
|
157
|
+
const hash2 = await Cipher.hashPassword("123456", { cost: 12 });
|
|
156
158
|
```
|
|
157
159
|
|
|
158
160
|
#### 验证密码
|
|
159
161
|
|
|
160
162
|
```typescript
|
|
161
|
-
const isValid = await Cipher.verifyPassword(
|
|
163
|
+
const isValid = await Cipher.verifyPassword("123456", storedHash);
|
|
162
164
|
if (isValid) {
|
|
163
165
|
// 密码正确
|
|
164
166
|
}
|
|
@@ -182,11 +184,11 @@ if (isValid) {
|
|
|
182
184
|
|
|
183
185
|
```typescript
|
|
184
186
|
// 编码
|
|
185
|
-
const encoded = Cipher.base64Encode(
|
|
187
|
+
const encoded = Cipher.base64Encode("hello");
|
|
186
188
|
// 'aGVsbG8='
|
|
187
189
|
|
|
188
190
|
// 解码
|
|
189
|
-
const decoded = Cipher.base64Decode(
|
|
191
|
+
const decoded = Cipher.base64Decode("aGVsbG8=");
|
|
190
192
|
// 'hello'
|
|
191
193
|
```
|
|
192
194
|
|
|
@@ -202,19 +204,19 @@ const random = Cipher.randomString(32);
|
|
|
202
204
|
|
|
203
205
|
```typescript
|
|
204
206
|
// 计算文件哈希(异步)
|
|
205
|
-
const fileHash = await Cipher.hashFile(
|
|
207
|
+
const fileHash = await Cipher.hashFile("/path/to/file.txt");
|
|
206
208
|
// 默认 SHA-256
|
|
207
209
|
|
|
208
210
|
// 指定算法
|
|
209
|
-
const md5Hash = await Cipher.hashFile(
|
|
211
|
+
const md5Hash = await Cipher.hashFile("/path/to/file.txt", "md5");
|
|
210
212
|
```
|
|
211
213
|
|
|
212
214
|
#### 快速哈希(非密码学)
|
|
213
215
|
|
|
214
216
|
```typescript
|
|
215
217
|
// 高性能哈希,用于数据指纹、去重等
|
|
216
|
-
const hash = Cipher.fastHash(
|
|
217
|
-
const hashWithSeed = Cipher.fastHash(
|
|
218
|
+
const hash = Cipher.fastHash("data");
|
|
219
|
+
const hashWithSeed = Cipher.fastHash("data", 12345);
|
|
218
220
|
```
|
|
219
221
|
|
|
220
222
|
---
|
|
@@ -226,12 +228,12 @@ JWT (JSON Web Token) 用于用户认证和 API 授权。
|
|
|
226
228
|
### 基本导入
|
|
227
229
|
|
|
228
230
|
```typescript
|
|
229
|
-
import { Jwt } from
|
|
231
|
+
import { Jwt } from "../lib/jwt.js";
|
|
230
232
|
|
|
231
233
|
const jwt = new Jwt({
|
|
232
|
-
secret:
|
|
233
|
-
expiresIn:
|
|
234
|
-
algorithm:
|
|
234
|
+
secret: "your-secret-key",
|
|
235
|
+
expiresIn: "7d",
|
|
236
|
+
algorithm: "HS256"
|
|
235
237
|
});
|
|
236
238
|
```
|
|
237
239
|
|
|
@@ -283,17 +285,17 @@ interface AuthConfig {
|
|
|
283
285
|
|
|
284
286
|
```typescript
|
|
285
287
|
// 基本用法
|
|
286
|
-
const token = jwt.sign({ userId: 123, role:
|
|
288
|
+
const token = jwt.sign({ userId: 123, role: "admin" });
|
|
287
289
|
|
|
288
290
|
// 自定义选项
|
|
289
291
|
const token2 = jwt.sign(
|
|
290
292
|
{ userId: 123 },
|
|
291
293
|
{
|
|
292
|
-
expiresIn:
|
|
293
|
-
issuer:
|
|
294
|
-
audience:
|
|
295
|
-
subject:
|
|
296
|
-
jwtId:
|
|
294
|
+
expiresIn: "1h",
|
|
295
|
+
issuer: "my-app",
|
|
296
|
+
audience: "users",
|
|
297
|
+
subject: "auth",
|
|
298
|
+
jwtId: "unique-id"
|
|
297
299
|
}
|
|
298
300
|
);
|
|
299
301
|
```
|
|
@@ -329,10 +331,10 @@ try {
|
|
|
329
331
|
const payload = jwt.verify(token, {
|
|
330
332
|
ignoreExpiration: false, // 是否忽略过期
|
|
331
333
|
ignoreNotBefore: false, // 是否忽略 nbf
|
|
332
|
-
issuer:
|
|
333
|
-
audience:
|
|
334
|
-
subject:
|
|
335
|
-
algorithms: [
|
|
334
|
+
issuer: "my-app", // 验证签发者
|
|
335
|
+
audience: "users", // 验证受众
|
|
336
|
+
subject: "auth", // 验证主题
|
|
337
|
+
algorithms: ["HS256"] // 允许的算法
|
|
336
338
|
});
|
|
337
339
|
```
|
|
338
340
|
|
|
@@ -361,11 +363,11 @@ console.log(decoded.signature); // 签名字符串
|
|
|
361
363
|
```typescript
|
|
362
364
|
// 通过 befly 访问
|
|
363
365
|
export default {
|
|
364
|
-
name:
|
|
366
|
+
name: "示例接口",
|
|
365
367
|
handler: async (befly, ctx) => {
|
|
366
|
-
const hash = befly.cipher.sha256(
|
|
368
|
+
const hash = befly.cipher.sha256("data");
|
|
367
369
|
const isValid = await befly.cipher.verifyPassword(password, storedHash);
|
|
368
|
-
return Yes(
|
|
370
|
+
return Yes("成功");
|
|
369
371
|
}
|
|
370
372
|
} as ApiRoute;
|
|
371
373
|
```
|
|
@@ -375,7 +377,7 @@ export default {
|
|
|
375
377
|
JWT 插件自动读取配置文件中的 `auth` 配置:
|
|
376
378
|
|
|
377
379
|
```json
|
|
378
|
-
// befly.
|
|
380
|
+
// befly.development.json
|
|
379
381
|
{
|
|
380
382
|
"auth": {
|
|
381
383
|
"secret": "your-dev-secret",
|
|
@@ -388,12 +390,12 @@ JWT 插件自动读取配置文件中的 `auth` 配置:
|
|
|
388
390
|
```typescript
|
|
389
391
|
// 通过 befly 访问
|
|
390
392
|
export default {
|
|
391
|
-
name:
|
|
393
|
+
name: "登录",
|
|
392
394
|
auth: false,
|
|
393
395
|
handler: async (befly, ctx) => {
|
|
394
396
|
// 签发令牌
|
|
395
397
|
const token = befly.jwt.sign({ userId: user.id, role: user.role });
|
|
396
|
-
return Yes(
|
|
398
|
+
return Yes("登录成功", { token: token });
|
|
397
399
|
}
|
|
398
400
|
} as ApiRoute;
|
|
399
401
|
```
|
|
@@ -406,27 +408,27 @@ export default {
|
|
|
406
408
|
|
|
407
409
|
```typescript
|
|
408
410
|
export default {
|
|
409
|
-
name:
|
|
411
|
+
name: "用户注册",
|
|
410
412
|
auth: false,
|
|
411
413
|
fields: {
|
|
412
|
-
email: { name:
|
|
413
|
-
password: { name:
|
|
414
|
+
email: { name: "邮箱", type: "string", regexp: "@email" },
|
|
415
|
+
password: { name: "密码", type: "string", min: 6, max: 100 }
|
|
414
416
|
},
|
|
415
|
-
required: [
|
|
417
|
+
required: ["email", "password"],
|
|
416
418
|
handler: async (befly, ctx) => {
|
|
417
419
|
// 加密密码
|
|
418
420
|
const hashedPassword = await befly.cipher.hashPassword(ctx.body.password);
|
|
419
421
|
|
|
420
422
|
// 存储用户
|
|
421
423
|
await befly.db.insData({
|
|
422
|
-
table:
|
|
424
|
+
table: "user",
|
|
423
425
|
data: {
|
|
424
426
|
email: ctx.body.email,
|
|
425
427
|
password: hashedPassword
|
|
426
428
|
}
|
|
427
429
|
});
|
|
428
430
|
|
|
429
|
-
return Yes(
|
|
431
|
+
return Yes("注册成功");
|
|
430
432
|
}
|
|
431
433
|
} as ApiRoute;
|
|
432
434
|
```
|
|
@@ -435,29 +437,29 @@ export default {
|
|
|
435
437
|
|
|
436
438
|
```typescript
|
|
437
439
|
export default {
|
|
438
|
-
name:
|
|
440
|
+
name: "用户登录",
|
|
439
441
|
auth: false,
|
|
440
442
|
fields: {
|
|
441
|
-
email: { name:
|
|
442
|
-
password: { name:
|
|
443
|
+
email: { name: "邮箱", type: "string", regexp: "@email" },
|
|
444
|
+
password: { name: "密码", type: "string", min: 6, max: 100 }
|
|
443
445
|
},
|
|
444
|
-
required: [
|
|
446
|
+
required: ["email", "password"],
|
|
445
447
|
handler: async (befly, ctx) => {
|
|
446
448
|
// 查询用户
|
|
447
449
|
const user = await befly.db.getDetail({
|
|
448
|
-
table:
|
|
449
|
-
columns: [
|
|
450
|
+
table: "user",
|
|
451
|
+
columns: ["id", "email", "password", "role"],
|
|
450
452
|
where: { email: ctx.body.email }
|
|
451
453
|
});
|
|
452
454
|
|
|
453
455
|
if (!user?.id) {
|
|
454
|
-
return No(
|
|
456
|
+
return No("用户不存在");
|
|
455
457
|
}
|
|
456
458
|
|
|
457
459
|
// 验证密码
|
|
458
460
|
const isValid = await befly.cipher.verifyPassword(ctx.body.password, user.password);
|
|
459
461
|
if (!isValid) {
|
|
460
|
-
return No(
|
|
462
|
+
return No("密码错误");
|
|
461
463
|
}
|
|
462
464
|
|
|
463
465
|
// 签发令牌
|
|
@@ -466,7 +468,7 @@ export default {
|
|
|
466
468
|
role: user.role
|
|
467
469
|
});
|
|
468
470
|
|
|
469
|
-
return Yes(
|
|
471
|
+
return Yes("登录成功", { token: token });
|
|
470
472
|
}
|
|
471
473
|
} as ApiRoute;
|
|
472
474
|
```
|
|
@@ -475,25 +477,25 @@ export default {
|
|
|
475
477
|
|
|
476
478
|
```typescript
|
|
477
479
|
export default {
|
|
478
|
-
name:
|
|
480
|
+
name: "第三方回调",
|
|
479
481
|
auth: false,
|
|
480
482
|
handler: async (befly, ctx) => {
|
|
481
483
|
const { data, signature, timestamp } = ctx.body;
|
|
482
484
|
|
|
483
485
|
// 验证时间戳(5分钟内有效)
|
|
484
486
|
if (Date.now() - timestamp > 5 * 60 * 1000) {
|
|
485
|
-
return No(
|
|
487
|
+
return No("请求已过期");
|
|
486
488
|
}
|
|
487
489
|
|
|
488
490
|
// 验证签名
|
|
489
|
-
const expectedSig = befly.cipher.hmacSha256(
|
|
491
|
+
const expectedSig = befly.cipher.hmacSha256("api-secret-key", `${data}${timestamp}`);
|
|
490
492
|
|
|
491
493
|
if (signature !== expectedSig) {
|
|
492
|
-
return No(
|
|
494
|
+
return No("签名验证失败");
|
|
493
495
|
}
|
|
494
496
|
|
|
495
497
|
// 处理业务逻辑
|
|
496
|
-
return Yes(
|
|
498
|
+
return Yes("验证成功");
|
|
497
499
|
}
|
|
498
500
|
} as ApiRoute;
|
|
499
501
|
```
|
|
@@ -502,7 +504,7 @@ export default {
|
|
|
502
504
|
|
|
503
505
|
```typescript
|
|
504
506
|
export default {
|
|
505
|
-
name:
|
|
507
|
+
name: "上传文件",
|
|
506
508
|
handler: async (befly, ctx) => {
|
|
507
509
|
const { filePath, expectedHash } = ctx.body;
|
|
508
510
|
|
|
@@ -510,10 +512,10 @@ export default {
|
|
|
510
512
|
const actualHash = await befly.cipher.hashFile(filePath);
|
|
511
513
|
|
|
512
514
|
if (actualHash !== expectedHash) {
|
|
513
|
-
return No(
|
|
515
|
+
return No("文件校验失败");
|
|
514
516
|
}
|
|
515
517
|
|
|
516
|
-
return Yes(
|
|
518
|
+
return Yes("文件校验通过");
|
|
517
519
|
}
|
|
518
520
|
} as ApiRoute;
|
|
519
521
|
```
|