befly 3.9.40 → 3.10.1

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 (144) hide show
  1. package/README.md +47 -19
  2. package/befly.config.ts +19 -2
  3. package/checks/checkApi.ts +79 -77
  4. package/checks/checkHook.ts +48 -0
  5. package/checks/checkMenu.ts +168 -0
  6. package/checks/checkPlugin.ts +48 -0
  7. package/checks/checkTable.ts +137 -183
  8. package/docs/README.md +17 -11
  9. package/docs/api/api.md +16 -2
  10. package/docs/guide/quickstart.md +31 -10
  11. package/docs/hooks/hook.md +2 -2
  12. package/docs/hooks/rateLimit.md +1 -1
  13. package/docs/infra/redis.md +26 -14
  14. package/docs/plugins/plugin.md +23 -21
  15. package/docs/quickstart.md +5 -328
  16. package/docs/reference/addon.md +0 -4
  17. package/docs/reference/config.md +14 -31
  18. package/docs/reference/logger.md +3 -3
  19. package/docs/reference/sync.md +132 -237
  20. package/docs/reference/table.md +28 -30
  21. package/hooks/auth.ts +3 -4
  22. package/hooks/cors.ts +4 -6
  23. package/hooks/parser.ts +3 -4
  24. package/hooks/permission.ts +3 -4
  25. package/hooks/validator.ts +3 -4
  26. package/lib/cacheHelper.ts +89 -153
  27. package/lib/cacheKeys.ts +1 -1
  28. package/lib/connect.ts +9 -13
  29. package/lib/dbDialect.ts +285 -0
  30. package/lib/dbHelper.ts +179 -507
  31. package/lib/dbUtils.ts +450 -0
  32. package/lib/logger.ts +41 -5
  33. package/lib/redisHelper.ts +1 -0
  34. package/lib/sqlBuilder.ts +358 -58
  35. package/lib/sqlCheck.ts +136 -0
  36. package/lib/validator.ts +1 -1
  37. package/loader/loadApis.ts +23 -126
  38. package/loader/loadHooks.ts +31 -46
  39. package/loader/loadPlugins.ts +37 -52
  40. package/main.ts +58 -19
  41. package/package.json +24 -25
  42. package/paths.ts +14 -14
  43. package/plugins/cache.ts +12 -6
  44. package/plugins/cipher.ts +2 -2
  45. package/plugins/config.ts +6 -8
  46. package/plugins/db.ts +14 -19
  47. package/plugins/jwt.ts +6 -7
  48. package/plugins/logger.ts +7 -9
  49. package/plugins/redis.ts +8 -10
  50. package/plugins/tool.ts +3 -4
  51. package/router/api.ts +3 -2
  52. package/router/static.ts +7 -5
  53. package/sync/syncApi.ts +80 -235
  54. package/sync/syncCache.ts +16 -0
  55. package/sync/syncDev.ts +167 -202
  56. package/sync/syncMenu.ts +230 -444
  57. package/sync/syncTable.ts +1247 -0
  58. package/tests/_mocks/mockSqliteDb.ts +204 -0
  59. package/tests/addonHelper-cache.test.ts +32 -0
  60. package/tests/apiHandler-routePath-only.test.ts +32 -0
  61. package/tests/cacheHelper.test.ts +16 -51
  62. package/tests/checkApi-routePath-strict.test.ts +166 -0
  63. package/tests/checkMenu.test.ts +346 -0
  64. package/tests/checkTable-smoke.test.ts +157 -0
  65. package/tests/dbDialect-cache.test.ts +23 -0
  66. package/tests/dbDialect.test.ts +46 -0
  67. package/tests/dbHelper-advanced.test.ts +1 -1
  68. package/tests/dbHelper-all-array-types.test.ts +15 -15
  69. package/tests/dbHelper-batch-write.test.ts +90 -0
  70. package/tests/dbHelper-columns.test.ts +36 -54
  71. package/tests/dbHelper-execute.test.ts +26 -26
  72. package/tests/dbHelper-joins.test.ts +85 -176
  73. package/tests/fixtures/scanFilesAddon/node_modules/@befly-addon/demo/apis/sub/b.ts +3 -0
  74. package/tests/fixtures/scanFilesApis/a.ts +3 -0
  75. package/tests/fixtures/scanFilesApis/sub/b.ts +3 -0
  76. package/tests/loadPlugins-order-smoke.test.ts +75 -0
  77. package/tests/logger.test.ts +6 -6
  78. package/tests/redisHelper.test.ts +6 -1
  79. package/tests/scanFiles-routePath.test.ts +46 -0
  80. package/tests/smoke-sql.test.ts +24 -0
  81. package/tests/sqlBuilder-advanced.test.ts +18 -5
  82. package/tests/sqlBuilder.test.ts +24 -0
  83. package/tests/sync-init-guard.test.ts +105 -0
  84. package/tests/syncApi-insBatch-fields-consistent.test.ts +61 -0
  85. package/tests/syncApi-obsolete-records.test.ts +69 -0
  86. package/tests/syncApi-type-compat.test.ts +72 -0
  87. package/tests/syncDev-permissions.test.ts +81 -0
  88. package/tests/syncMenu-disableMenus-hard-delete.test.ts +88 -0
  89. package/tests/syncMenu-duplicate-path.test.ts +122 -0
  90. package/tests/syncMenu-obsolete-records.test.ts +161 -0
  91. package/tests/syncMenu-parentPath-from-tree.test.ts +75 -0
  92. package/tests/syncMenu-paths.test.ts +0 -9
  93. package/tests/{syncDb-apply.test.ts → syncTable-apply.test.ts} +14 -24
  94. package/tests/{syncDb-array-number.test.ts → syncTable-array-number.test.ts} +31 -31
  95. package/tests/syncTable-constants.test.ts +101 -0
  96. package/tests/syncTable-db-integration.test.ts +237 -0
  97. package/tests/{syncDb-ddl.test.ts → syncTable-ddl.test.ts} +67 -53
  98. package/tests/{syncDb-helpers.test.ts → syncTable-helpers.test.ts} +12 -26
  99. package/tests/syncTable-schema.test.ts +99 -0
  100. package/tests/syncTable-testkit.test.ts +25 -0
  101. package/tests/syncTable-types.test.ts +122 -0
  102. package/tests/tableRef-and-deserialize.test.ts +67 -0
  103. package/tsconfig.json +1 -1
  104. package/types/api.d.ts +1 -1
  105. package/types/befly.d.ts +13 -12
  106. package/types/cache.d.ts +2 -2
  107. package/types/context.d.ts +1 -1
  108. package/types/database.d.ts +0 -5
  109. package/types/hook.d.ts +1 -10
  110. package/types/plugin.d.ts +2 -96
  111. package/types/sync.d.ts +19 -25
  112. package/utils/convertBigIntFields.ts +38 -0
  113. package/utils/disableMenusGlob.ts +85 -0
  114. package/utils/importDefault.ts +21 -0
  115. package/utils/isDirentDirectory.ts +23 -0
  116. package/utils/loadMenuConfigs.ts +145 -0
  117. package/utils/processFields.ts +25 -0
  118. package/utils/scanAddons.ts +72 -0
  119. package/utils/scanFiles.ts +129 -21
  120. package/utils/scanSources.ts +64 -0
  121. package/utils/sortModules.ts +137 -0
  122. package/checks/checkApp.ts +0 -55
  123. package/docs/cipher.md +0 -582
  124. package/docs/database.md +0 -1176
  125. package/hooks/rateLimit.ts +0 -276
  126. package/sync/syncAll.ts +0 -35
  127. package/sync/syncDb/apply.ts +0 -192
  128. package/sync/syncDb/constants.ts +0 -119
  129. package/sync/syncDb/ddl.ts +0 -251
  130. package/sync/syncDb/helpers.ts +0 -84
  131. package/sync/syncDb/schema.ts +0 -202
  132. package/sync/syncDb/sqlite.ts +0 -48
  133. package/sync/syncDb/table.ts +0 -207
  134. package/sync/syncDb/tableCreate.ts +0 -163
  135. package/sync/syncDb/types.ts +0 -132
  136. package/sync/syncDb/version.ts +0 -69
  137. package/sync/syncDb.ts +0 -168
  138. package/tests/rateLimit-hook.test.ts +0 -477
  139. package/tests/syncDb-constants.test.ts +0 -130
  140. package/tests/syncDb-schema.test.ts +0 -179
  141. package/tests/syncDb-types.test.ts +0 -139
  142. package/utils/addonHelper.ts +0 -90
  143. package/utils/modules.ts +0 -98
  144. package/utils/route.ts +0 -23
package/docs/cipher.md DELETED
@@ -1,582 +0,0 @@
1
- # Cipher 加密工具
2
-
3
- > 哈希、签名、密码加密与 JWT 令牌
4
-
5
- > 本文档已迁移到:[`./plugins/cipher.md`](./plugins/cipher.md)
6
-
7
- ## 目录
8
-
9
- - [概述](#概述)
10
- - [Cipher 加密类](#cipher-加密类)
11
- - [哈希算法](#哈希算法)
12
- - [HMAC 签名](#hmac-签名)
13
- - [密码加密](#密码加密)
14
- - [工具方法](#工具方法)
15
- - [JWT 令牌](#jwt-令牌)
16
- - [配置选项](#配置选项)
17
- - [签发令牌](#签发令牌)
18
- - [验证令牌](#验证令牌)
19
- - [解码令牌](#解码令牌)
20
- - [插件集成](#插件集成)
21
- - [使用示例](#使用示例)
22
- - [FAQ](#faq)
23
-
24
- ---
25
-
26
- ## 概述
27
-
28
- Befly 提供两个安全相关的工具:
29
-
30
- | 工具 | 说明 | 典型场景 |
31
- | -------- | ---------- | ------------------------ |
32
- | `Cipher` | 加密工具类 | 数据哈希、签名、密码加密 |
33
- | `Jwt` | JWT 令牌类 | 用户认证、API 授权 |
34
-
35
- ---
36
-
37
- ## Cipher 加密类
38
-
39
- ### 基本导入
40
-
41
- ```typescript
42
- import { Cipher } from "../lib/cipher.js";
43
- ```
44
-
45
- ### 哈希算法
46
-
47
- #### MD5
48
-
49
- ```typescript
50
- // 基本用法
51
- const hash = Cipher.md5("hello");
52
- // '5d41402abc4b2a76b9719d911017c592'
53
-
54
- // 指定编码
55
- const hashBase64 = Cipher.md5("hello", "base64");
56
- ```
57
-
58
- #### SHA-1
59
-
60
- ```typescript
61
- const hash = Cipher.sha1("hello");
62
- // 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
63
- ```
64
-
65
- #### SHA-256
66
-
67
- ```typescript
68
- const hash = Cipher.sha256("hello");
69
- // '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
70
- ```
71
-
72
- #### SHA-512
73
-
74
- ```typescript
75
- const hash = Cipher.sha512("hello");
76
- // '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca...'
77
- ```
78
-
79
- #### 通用哈希
80
-
81
- ```typescript
82
- // 支持多种算法
83
- const hash = Cipher.hash("sha256", "hello");
84
- const hash2 = Cipher.hash("sha384", "hello");
85
- const hash3 = Cipher.hash("blake2b256", "hello");
86
- ```
87
-
88
- #### 支持的算法
89
-
90
- | 算法 | 输出长度 | 说明 |
91
- | ------------ | -------- | ------------------ |
92
- | `md5` | 32 | 不推荐用于安全场景 |
93
- | `sha1` | 40 | 不推荐用于安全场景 |
94
- | `sha256` | 64 | 推荐 |
95
- | `sha384` | 96 | 高安全性 |
96
- | `sha512` | 128 | 高安全性 |
97
- | `blake2b256` | 64 | 高性能 |
98
- | `blake2b512` | 128 | 高性能 |
99
-
100
- #### 输出编码
101
-
102
- | 编码 | 说明 |
103
- | ----------- | ----------------- |
104
- | `hex` | 十六进制(默认) |
105
- | `base64` | Base64 编码 |
106
- | `base64url` | URL 安全的 Base64 |
107
-
108
- ### HMAC 签名
109
-
110
- HMAC 使用密钥进行签名,用于数据完整性验证:
111
-
112
- ```typescript
113
- const key = "my-secret-key";
114
-
115
- // HMAC-MD5
116
- const sig1 = Cipher.hmacMd5(key, "data");
117
-
118
- // HMAC-SHA1
119
- const sig2 = Cipher.hmacSha1(key, "data");
120
-
121
- // HMAC-SHA256(推荐)
122
- const sig3 = Cipher.hmacSha256(key, "data");
123
-
124
- // HMAC-SHA512
125
- const sig4 = Cipher.hmacSha512(key, "data");
126
-
127
- // 通用 HMAC
128
- const sig5 = Cipher.hmac("sha256", key, "data");
129
- ```
130
-
131
- #### RSA-SHA256 签名
132
-
133
- 用于非对称加密签名:
134
-
135
- ```typescript
136
- const privateKey = `-----BEGIN PRIVATE KEY-----
137
- MIIEvQIBADANBg...
138
- -----END PRIVATE KEY-----`;
139
-
140
- const signature = Cipher.rsaSha256("data to sign", privateKey);
141
- // 或指定编码
142
- const signatureBase64 = Cipher.rsaSha256("data to sign", privateKey, "base64");
143
- ```
144
-
145
- ### 密码加密
146
-
147
- 使用 bcrypt 算法加密密码(推荐用于用户密码存储):
148
-
149
- #### 加密密码
150
-
151
- ```typescript
152
- // 默认配置(推荐)
153
- const hash = await Cipher.hashPassword("123456");
154
- // '$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92...'
155
-
156
- // 自定义强度(cost 越高越安全但越慢)
157
- const hash2 = await Cipher.hashPassword("123456", { cost: 12 });
158
- ```
159
-
160
- #### 验证密码
161
-
162
- ```typescript
163
- const isValid = await Cipher.verifyPassword("123456", storedHash);
164
- if (isValid) {
165
- // 密码正确
166
- }
167
- ```
168
-
169
- #### bcrypt 参数说明
170
-
171
- | 参数 | 默认值 | 说明 |
172
- | ------ | ------ | ------------------- |
173
- | `cost` | 10 | 计算强度,范围 4-31 |
174
-
175
- **cost 选择建议**:
176
-
177
- - `10`:一般应用(默认)
178
- - `12`:高安全性应用
179
- - `14+`:极高安全性(性能影响较大)
180
-
181
- ### 工具方法
182
-
183
- #### Base64 编解码
184
-
185
- ```typescript
186
- // 编码
187
- const encoded = Cipher.base64Encode("hello");
188
- // 'aGVsbG8='
189
-
190
- // 解码
191
- const decoded = Cipher.base64Decode("aGVsbG8=");
192
- // 'hello'
193
- ```
194
-
195
- #### 随机字符串
196
-
197
- ```typescript
198
- // 生成指定长度的随机十六进制字符串
199
- const random = Cipher.randomString(32);
200
- // 'a1b2c3d4e5f6...'(32位)
201
- ```
202
-
203
- #### 文件哈希
204
-
205
- ```typescript
206
- // 计算文件哈希(异步)
207
- const fileHash = await Cipher.hashFile("/path/to/file.txt");
208
- // 默认 SHA-256
209
-
210
- // 指定算法
211
- const md5Hash = await Cipher.hashFile("/path/to/file.txt", "md5");
212
- ```
213
-
214
- #### 快速哈希(非密码学)
215
-
216
- ```typescript
217
- // 高性能哈希,用于数据指纹、去重等
218
- const hash = Cipher.fastHash("data");
219
- const hashWithSeed = Cipher.fastHash("data", 12345);
220
- ```
221
-
222
- ---
223
-
224
- ## JWT 令牌
225
-
226
- JWT (JSON Web Token) 用于用户认证和 API 授权。
227
-
228
- ### 基本导入
229
-
230
- ```typescript
231
- import { Jwt } from "../lib/jwt.js";
232
-
233
- const jwt = new Jwt({
234
- secret: "your-secret-key",
235
- expiresIn: "7d",
236
- algorithm: "HS256"
237
- });
238
- ```
239
-
240
- ### 配置选项
241
-
242
- #### AuthConfig 接口
243
-
244
- ```typescript
245
- interface AuthConfig {
246
- secret?: string; // 密钥
247
- expiresIn?: string; // 过期时间
248
- algorithm?: string; // 签名算法
249
- }
250
- ```
251
-
252
- #### 配置说明
253
-
254
- | 属性 | 默认值 | 说明 |
255
- | ----------- | ---------------- | ---------------------------- |
256
- | `secret` | `'befly-secret'` | JWT 密钥(生产环境必须修改) |
257
- | `expiresIn` | `'7d'` | 过期时间 |
258
- | `algorithm` | `'HS256'` | 签名算法 |
259
-
260
- #### 过期时间格式
261
-
262
- | 格式 | 示例 | 说明 |
263
- | ---- | ------- | ------- |
264
- | 秒 | `3600` | 3600 秒 |
265
- | 分钟 | `'30m'` | 30 分钟 |
266
- | 小时 | `'2h'` | 2 小时 |
267
- | 天 | `'7d'` | 7 天 |
268
- | 周 | `'2w'` | 2 周 |
269
-
270
- #### 支持的算法
271
-
272
- | 算法 | 类型 | 说明 |
273
- | ------- | ------ | -------------------- |
274
- | `HS256` | 对称 | HMAC SHA-256(默认) |
275
- | `HS384` | 对称 | HMAC SHA-384 |
276
- | `HS512` | 对称 | HMAC SHA-512 |
277
- | `RS256` | 非对称 | RSA SHA-256 |
278
- | `RS384` | 非对称 | RSA SHA-384 |
279
- | `RS512` | 非对称 | RSA SHA-512 |
280
- | `ES256` | 非对称 | ECDSA SHA-256 |
281
- | `ES384` | 非对称 | ECDSA SHA-384 |
282
- | `ES512` | 非对称 | ECDSA SHA-512 |
283
-
284
- ### 签发令牌
285
-
286
- ```typescript
287
- // 基本用法
288
- const token = jwt.sign({ userId: 123, role: "admin" });
289
-
290
- // 自定义选项
291
- const token2 = jwt.sign(
292
- { userId: 123 },
293
- {
294
- expiresIn: "1h",
295
- issuer: "my-app",
296
- audience: "users",
297
- subject: "auth",
298
- jwtId: "unique-id"
299
- }
300
- );
301
- ```
302
-
303
- #### JwtSignOptions
304
-
305
- | 属性 | 类型 | 说明 |
306
- | ----------- | ------ | ---------------- |
307
- | `expiresIn` | string | 覆盖默认过期时间 |
308
- | `secret` | string | 覆盖默认密钥 |
309
- | `algorithm` | string | 覆盖默认算法 |
310
- | `issuer` | string | 签发者 (iss) |
311
- | `audience` | string | 受众 (aud) |
312
- | `subject` | string | 主题 (sub) |
313
- | `jwtId` | string | 唯一标识 (jti) |
314
- | `notBefore` | number | 生效时间 (nbf) |
315
-
316
- ### 验证令牌
317
-
318
- ```typescript
319
- try {
320
- const payload = jwt.verify(token);
321
- console.log(payload.userId); // 123
322
- } catch (error) {
323
- // 令牌无效或已过期
324
- console.error(error.message);
325
- }
326
- ```
327
-
328
- #### JwtVerifyOptions
329
-
330
- ```typescript
331
- const payload = jwt.verify(token, {
332
- ignoreExpiration: false, // 是否忽略过期
333
- ignoreNotBefore: false, // 是否忽略 nbf
334
- issuer: "my-app", // 验证签发者
335
- audience: "users", // 验证受众
336
- subject: "auth", // 验证主题
337
- algorithms: ["HS256"] // 允许的算法
338
- });
339
- ```
340
-
341
- ### 解码令牌
342
-
343
- 解码不验证签名,仅解析内容:
344
-
345
- ```typescript
346
- // 只获取 payload
347
- const payload = jwt.decode(token);
348
- console.log(payload.userId);
349
-
350
- // 获取完整信息
351
- const decoded = jwt.decode(token, true);
352
- console.log(decoded.header); // { alg: 'HS256', typ: 'JWT' }
353
- console.log(decoded.payload); // { userId: 123, iat: ..., exp: ... }
354
- console.log(decoded.signature); // 签名字符串
355
- ```
356
-
357
- ---
358
-
359
- ## 插件集成
360
-
361
- ### Cipher 插件
362
-
363
- ```typescript
364
- // 通过 befly 访问
365
- export default {
366
- name: "示例接口",
367
- handler: async (befly, ctx) => {
368
- const hash = befly.cipher.sha256("data");
369
- const isValid = await befly.cipher.verifyPassword(password, storedHash);
370
- return Yes("成功");
371
- }
372
- } as ApiRoute;
373
- ```
374
-
375
- ### JWT 插件
376
-
377
- JWT 插件自动读取配置文件中的 `auth` 配置:
378
-
379
- ```json
380
- // befly.development.json
381
- {
382
- "auth": {
383
- "secret": "your-dev-secret",
384
- "expiresIn": "7d",
385
- "algorithm": "HS256"
386
- }
387
- }
388
- ```
389
-
390
- ```typescript
391
- // 通过 befly 访问
392
- export default {
393
- name: "登录",
394
- auth: false,
395
- handler: async (befly, ctx) => {
396
- // 签发令牌
397
- const token = befly.jwt.sign({ userId: user.id, role: user.role });
398
- return Yes("登录成功", { token: token });
399
- }
400
- } as ApiRoute;
401
- ```
402
-
403
- ---
404
-
405
- ## 使用示例
406
-
407
- ### 示例 1:用户注册
408
-
409
- ```typescript
410
- export default {
411
- name: "用户注册",
412
- auth: false,
413
- fields: {
414
- email: { name: "邮箱", type: "string", regexp: "@email" },
415
- password: { name: "密码", type: "string", min: 6, max: 100 }
416
- },
417
- required: ["email", "password"],
418
- handler: async (befly, ctx) => {
419
- // 加密密码
420
- const hashedPassword = await befly.cipher.hashPassword(ctx.body.password);
421
-
422
- // 存储用户
423
- await befly.db.insData({
424
- table: "user",
425
- data: {
426
- email: ctx.body.email,
427
- password: hashedPassword
428
- }
429
- });
430
-
431
- return Yes("注册成功");
432
- }
433
- } as ApiRoute;
434
- ```
435
-
436
- ### 示例 2:用户登录
437
-
438
- ```typescript
439
- export default {
440
- name: "用户登录",
441
- auth: false,
442
- fields: {
443
- email: { name: "邮箱", type: "string", regexp: "@email" },
444
- password: { name: "密码", type: "string", min: 6, max: 100 }
445
- },
446
- required: ["email", "password"],
447
- handler: async (befly, ctx) => {
448
- // 查询用户
449
- const user = await befly.db.getDetail({
450
- table: "user",
451
- columns: ["id", "email", "password", "role"],
452
- where: { email: ctx.body.email }
453
- });
454
-
455
- if (!user?.id) {
456
- return No("用户不存在");
457
- }
458
-
459
- // 验证密码
460
- const isValid = await befly.cipher.verifyPassword(ctx.body.password, user.password);
461
- if (!isValid) {
462
- return No("密码错误");
463
- }
464
-
465
- // 签发令牌
466
- const token = befly.jwt.sign({
467
- userId: user.id,
468
- role: user.role
469
- });
470
-
471
- return Yes("登录成功", { token: token });
472
- }
473
- } as ApiRoute;
474
- ```
475
-
476
- ### 示例 3:API 签名验证
477
-
478
- ```typescript
479
- export default {
480
- name: "第三方回调",
481
- auth: false,
482
- handler: async (befly, ctx) => {
483
- const { data, signature, timestamp } = ctx.body;
484
-
485
- // 验证时间戳(5分钟内有效)
486
- if (Date.now() - timestamp > 5 * 60 * 1000) {
487
- return No("请求已过期");
488
- }
489
-
490
- // 验证签名
491
- const expectedSig = befly.cipher.hmacSha256("api-secret-key", `${data}${timestamp}`);
492
-
493
- if (signature !== expectedSig) {
494
- return No("签名验证失败");
495
- }
496
-
497
- // 处理业务逻辑
498
- return Yes("验证成功");
499
- }
500
- } as ApiRoute;
501
- ```
502
-
503
- ### 示例 4:文件完整性校验
504
-
505
- ```typescript
506
- export default {
507
- name: "上传文件",
508
- handler: async (befly, ctx) => {
509
- const { filePath, expectedHash } = ctx.body;
510
-
511
- // 计算文件哈希
512
- const actualHash = await befly.cipher.hashFile(filePath);
513
-
514
- if (actualHash !== expectedHash) {
515
- return No("文件校验失败");
516
- }
517
-
518
- return Yes("文件校验通过");
519
- }
520
- } as ApiRoute;
521
- ```
522
-
523
- ---
524
-
525
- ## FAQ
526
-
527
- ### Q: 密码应该用什么算法加密?
528
-
529
- A: 使用 `hashPassword` 方法(bcrypt 算法)。不要使用 MD5、SHA 等哈希算法存储密码。
530
-
531
- ### Q: JWT secret 应该如何设置?
532
-
533
- A:
534
-
535
- 1. 生产环境必须使用强密钥(32 字符以上随机字符串)
536
- 2. 密钥应通过环境变量或配置文件注入
537
- 3. 不要在代码中硬编码密钥
538
-
539
- ```bash
540
- # 生成随机密钥
541
- node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
542
- ```
543
-
544
- ### Q: JWT 过期后如何处理?
545
-
546
- A:
547
-
548
- 1. 客户端检测到 401 错误后引导用户重新登录
549
- 2. 或实现 refresh token 机制
550
-
551
- ### Q: MD5 和 SHA1 还能用吗?
552
-
553
- A:
554
-
555
- - **不要用于安全场景**(密码、签名等)
556
- - 可以用于非安全场景(文件指纹、缓存键等)
557
- - 推荐使用 SHA-256 或更高
558
-
559
- ### Q: HMAC 和普通哈希有什么区别?
560
-
561
- A:
562
-
563
- - **哈希**:单向转换,任何人都能计算
564
- - **HMAC**:带密钥的签名,只有知道密钥才能计算
565
- - HMAC 用于验证数据完整性和来源
566
-
567
- ### Q: 如何选择 JWT 算法?
568
-
569
- A:
570
-
571
- - **HS256**:对称算法,简单高效,适合单服务
572
- - **RS256**:非对称算法,适合微服务(私钥签发,公钥验证)
573
- - **ES256**:椭圆曲线,签名更短,性能更好
574
-
575
- ### Q: bcrypt cost 参数如何选择?
576
-
577
- A:
578
-
579
- - 参考标准:单次验证耗时约 100-300ms
580
- - 一般应用:`cost=10`(默认)
581
- - 高安全性:`cost=12`
582
- - 每增加 1,耗时翻倍