sumor 3.3.2 → 3.3.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.
Files changed (70) hide show
  1. package/README.md +53 -0
  2. package/README.zh-CN.md +61 -7
  3. package/dist/server/controllers/logoutController.js +2 -2
  4. package/dist/server/controllers/mock/avatarController.d.ts +8 -0
  5. package/dist/server/controllers/mock/avatarController.d.ts.map +1 -0
  6. package/dist/server/controllers/mock/avatarController.js +15 -0
  7. package/dist/server/controllers/mock/avatarController.js.map +1 -0
  8. package/dist/server/controllers/mock/loginController.d.ts +8 -0
  9. package/dist/server/controllers/mock/loginController.d.ts.map +1 -0
  10. package/dist/server/controllers/mock/loginController.js +34 -0
  11. package/dist/server/controllers/mock/loginController.js.map +1 -0
  12. package/dist/server/controllers/mock/logoutController.d.ts +8 -0
  13. package/dist/server/controllers/mock/logoutController.d.ts.map +1 -0
  14. package/dist/server/controllers/mock/logoutController.js +17 -0
  15. package/dist/server/controllers/mock/logoutController.js.map +1 -0
  16. package/dist/server/controllers/mock/navController.d.ts +8 -0
  17. package/dist/server/controllers/mock/navController.d.ts.map +1 -0
  18. package/dist/server/controllers/mock/navController.js +93 -0
  19. package/dist/server/controllers/mock/navController.js.map +1 -0
  20. package/dist/server/controllers/mock/tokenController.d.ts +8 -0
  21. package/dist/server/controllers/mock/tokenController.d.ts.map +1 -0
  22. package/dist/server/controllers/mock/tokenController.js +89 -0
  23. package/dist/server/controllers/mock/tokenController.js.map +1 -0
  24. package/dist/server/controllers/oauthCallbackController.js +2 -2
  25. package/dist/server/controllers/tokenRefreshController.js +2 -2
  26. package/dist/server/index.d.ts +1 -1
  27. package/dist/server/index.js +2 -2
  28. package/dist/server/mock/mockConfig.d.ts +2 -4
  29. package/dist/server/mock/mockConfig.d.ts.map +1 -1
  30. package/dist/server/mock/mockConfig.js +11 -20
  31. package/dist/server/mock/mockConfig.js.map +1 -1
  32. package/dist/server/mock/mockRoutes.d.ts +13 -3
  33. package/dist/server/mock/mockRoutes.d.ts.map +1 -1
  34. package/dist/server/mock/mockRoutes.js +23 -85
  35. package/dist/server/mock/mockRoutes.js.map +1 -1
  36. package/dist/server/models/blacklistModel.js +2 -2
  37. package/dist/server/models/jwksModel.js +2 -2
  38. package/dist/server/routes.d.ts +1 -2
  39. package/dist/server/routes.d.ts.map +1 -1
  40. package/dist/server/routes.js +21 -29
  41. package/dist/server/routes.js.map +1 -1
  42. package/dist/server/services/OAuthService.d.ts +24 -0
  43. package/dist/server/services/OAuthService.d.ts.map +1 -0
  44. package/dist/server/services/OAuthService.js +32 -0
  45. package/dist/server/services/OAuthService.js.map +1 -0
  46. package/dist/server/services/oauth/MockDataGenerator.d.ts +18 -0
  47. package/dist/server/services/oauth/MockDataGenerator.d.ts.map +1 -0
  48. package/dist/server/services/oauth/MockDataGenerator.js +39 -0
  49. package/dist/server/services/oauth/MockDataGenerator.js.map +1 -0
  50. package/dist/server/services/oauth/OAuthMockService.d.ts +28 -0
  51. package/dist/server/services/oauth/OAuthMockService.d.ts.map +1 -0
  52. package/dist/server/services/oauth/OAuthMockService.js +184 -0
  53. package/dist/server/services/oauth/OAuthMockService.js.map +1 -0
  54. package/dist/server/services/oauth/OAuthProductionService.d.ts +22 -0
  55. package/dist/server/services/oauth/OAuthProductionService.d.ts.map +1 -0
  56. package/dist/server/services/oauth/OAuthProductionService.js +203 -0
  57. package/dist/server/services/oauth/OAuthProductionService.js.map +1 -0
  58. package/dist/server/services/oauth/OAuthServiceError.d.ts +9 -0
  59. package/dist/server/services/oauth/OAuthServiceError.d.ts.map +1 -0
  60. package/dist/server/services/oauth/OAuthServiceError.js +16 -0
  61. package/dist/server/services/oauth/OAuthServiceError.js.map +1 -0
  62. package/package.json +1 -1
  63. package/dist/server/mock/mockApiRoutes.d.ts +0 -14
  64. package/dist/server/mock/mockApiRoutes.d.ts.map +0 -1
  65. package/dist/server/mock/mockApiRoutes.js +0 -149
  66. package/dist/server/mock/mockApiRoutes.js.map +0 -1
  67. package/dist/server/services/oauthService.d.ts +0 -149
  68. package/dist/server/services/oauthService.d.ts.map +0 -1
  69. package/dist/server/services/oauthService.js +0 -360
  70. package/dist/server/services/oauthService.js.map +0 -1
package/README.md CHANGED
@@ -445,6 +445,43 @@ OAUTH_MOCK_USER_IS_VERIFIED=1
445
445
 
446
446
  ### Example Mock Setup
447
447
 
448
+ #### Mock Users List
449
+
450
+ To populate the `getUserInfo()`, `getUsersInfo()`, and `searchUsers()` methods with test data, configure the `OAUTH_MOCK_USERS` environment variable with a JSON array of user objects.
451
+
452
+ **User object properties:**
453
+
454
+ ```typescript
455
+ interface MockUser {
456
+ userId: string // Required: unique user identifier
457
+ username?: string // Optional: defaults to `user_{userId}`
458
+ email?: string // Optional: defaults to `{userId}@example.com`
459
+ name?: string // Optional: defaults to `User {userId}`
460
+ avatar?: string // Optional: avatar URL
461
+ phone?: string // Optional: phone number
462
+ createdAt?: string // Optional: ISO 8601 timestamp
463
+ updatedAt?: string // Optional: ISO 8601 timestamp
464
+ isActive?: boolean // Optional: defaults to `true`
465
+ }
466
+ ```
467
+
468
+ **Behavior:**
469
+
470
+ - `getUserInfo('user001')` returns the configured user object if it exists, otherwise generates a default user
471
+ - `getUsersInfo(['user001', 'unknown'])` returns configured users for known IDs and generated users for unknown IDs
472
+ - `searchUsers('alice')` searches configured users by userId, username, name, or email and returns matches
473
+
474
+ **Configuration example:**
475
+
476
+ ```bash
477
+ export OAUTH_MOCK_USERS='[
478
+ {"userId": "user001", "username": "alice", "email": "alice@example.com", "name": "Alice Wang"},
479
+ {"userId": "user002", "username": "bob", "email": "bob@example.com", "name": "Bob Smith"}
480
+ ]'
481
+ ```
482
+
483
+ For comprehensive examples and usage patterns, refer to [Mock Users List Usage Guide](server/services/oauth/MOCK_USERS_USAGE.md).
484
+
448
485
  **.env.development:**
449
486
 
450
487
  ```bash
@@ -453,6 +490,22 @@ OAUTH_MOCK_USER_ID=dev-user-1
453
490
  OAUTH_MOCK_USER_ROLES=admin
454
491
  OAUTH_MOCK_USER_PERMISSIONS=posts:view,posts:edit,posts:delete
455
492
  OAUTH_MOCK_USER_IS_VERIFIED=1
493
+ OAUTH_MOCK_USERS='[
494
+ {
495
+ "userId": "user001",
496
+ "username": "alice",
497
+ "email": "alice@example.com",
498
+ "name": "Alice Wang",
499
+ "avatar": "https://api.example.com/avatars/alice.jpg",
500
+ "isActive": true
501
+ },
502
+ {
503
+ "userId": "user002",
504
+ "username": "bob",
505
+ "email": "bob@example.com",
506
+ "name": "Bob Smith"
507
+ }
508
+ ]'
456
509
  ```
457
510
 
458
511
  No changes are needed in application code — the same `oauthRoutes`, `loadJwtUserMiddleware`, `login()`, and `logout()` calls work in both mock and production modes.
package/README.zh-CN.md CHANGED
@@ -425,13 +425,14 @@ OAUTH_MOCK_USER_PERMISSIONS=
425
425
  OAUTH_MOCK_USER_IS_VERIFIED=1
426
426
  ```
427
427
 
428
- | 变量 | 默认值 | 说明 |
429
- | ----------------------------- | --------------- | --------------------------- |
430
- | `OAUTH_MOCK` | `false` | 设为 `true` 启用 Mock 模式 |
431
- | `OAUTH_MOCK_USER_ID` | `mock-user-001` | Mock 用户 ID |
432
- | `OAUTH_MOCK_USER_ROLES` | `admin` | 逗号分隔的 Mock 角色 |
433
- | `OAUTH_MOCK_USER_PERMISSIONS` | _(空)_ | 逗号分隔的 Mock 权限 |
434
- | `OAUTH_MOCK_USER_IS_VERIFIED` | `1` | Mock 认证状态(`0` 或 `1`) |
428
+ | 变量 | 默认值 | 说明 |
429
+ | ----------------------------- | --------------- | ------------------------------------------- |
430
+ | `OAUTH_MOCK` | `false` | 设为 `true` 启用 Mock 模式 |
431
+ | `OAUTH_MOCK_USER_ID` | `mock-user-001` | Mock 用户 ID |
432
+ | `OAUTH_MOCK_USER_ROLES` | `admin` | 逗号分隔的 Mock 角色 |
433
+ | `OAUTH_MOCK_USER_PERMISSIONS` | _(空)_ | 逗号分隔的 Mock 权限 |
434
+ | `OAUTH_MOCK_USER_IS_VERIFIED` | `1` | Mock 认证状态(`0` 或 `1`) |
435
+ | `OAUTH_MOCK_USERS` | _(空)_ | JSON 数组格式的 Mock 用户列表用于搜索和查询 |
435
436
 
436
437
  ### Mock 专用路由(仅在 `OAUTH_MOCK=true` 时注册)
437
438
 
@@ -444,6 +445,43 @@ OAUTH_MOCK_USER_IS_VERIFIED=1
444
445
 
445
446
  ### Mock 模式示例配置
446
447
 
448
+ #### Mock 用户列表
449
+
450
+ 通过配置 `OAUTH_MOCK_USERS` 环境变量为 `getUserInfo()`、`getUsersInfo()` 和 `searchUsers()` 方法提供测试数据,无需真实 OAuth 服务。
451
+
452
+ **用户对象属性:**
453
+
454
+ ```typescript
455
+ interface MockUser {
456
+ userId: string // 必需:用户唯一标识
457
+ username?: string // 可选:默认为 `user_{userId}`
458
+ email?: string // 可选:默认为 `{userId}@example.com`
459
+ name?: string // 可选:默认为 `User {userId}`
460
+ avatar?: string // 可选:头像 URL
461
+ phone?: string // 可选:电话号码
462
+ createdAt?: string // 可选:ISO 8601 时间戳
463
+ updatedAt?: string // 可选:ISO 8601 时间戳
464
+ isActive?: boolean // 可选:默认为 `true`
465
+ }
466
+ ```
467
+
468
+ **行为说明:**
469
+
470
+ - `getUserInfo('user001')` 返回配置的用户对象,不存在则生成默认用户
471
+ - `getUsersInfo(['user001', 'unknown'])` 返回已配置用户及动态生成的未知用户
472
+ - `searchUsers('alice')` 在配置用户中按 userId、username、name、email 模糊搜索并返回结果
473
+
474
+ **配置示例:**
475
+
476
+ ```bash
477
+ export OAUTH_MOCK_USERS='[
478
+ {"userId": "user001", "username": "alice", "email": "alice@example.com", "name": "Alice Wang"},
479
+ {"userId": "user002", "username": "bob", "email": "bob@example.com", "name": "Bob Smith"}
480
+ ]'
481
+ ```
482
+
483
+ 更详细的配置示例和使用模式参考 [Mock 用户列表使用指南](server/services/oauth/MOCK_USERS_USAGE.md)。
484
+
447
485
  **.env.development:**
448
486
 
449
487
  ```bash
@@ -452,6 +490,22 @@ OAUTH_MOCK_USER_ID=dev-user-1
452
490
  OAUTH_MOCK_USER_ROLES=admin
453
491
  OAUTH_MOCK_USER_PERMISSIONS=posts:view,posts:edit,posts:delete
454
492
  OAUTH_MOCK_USER_IS_VERIFIED=1
493
+ OAUTH_MOCK_USERS='[
494
+ {
495
+ "userId": "user001",
496
+ "username": "alice",
497
+ "email": "alice@example.com",
498
+ "name": "Alice Wang",
499
+ "avatar": "https://api.example.com/avatars/alice.jpg",
500
+ "isActive": true
501
+ },
502
+ {
503
+ "userId": "user002",
504
+ "username": "bob",
505
+ "email": "bob@example.com",
506
+ "name": "Bob Smith"
507
+ }
508
+ ]'
455
509
  ```
456
510
 
457
511
  应用代码无需任何修改 —— 相同的 `oauthRoutes`、`loadJwtUserMiddleware`、`login()` 和 `logout()` 调用在 Mock 模式和生产模式下均正常工作。
@@ -7,7 +7,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
7
7
  };
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.logout = logout;
10
- const oauthService_1 = __importDefault(require("../services/oauthService"));
10
+ const OAuthService_1 = __importDefault(require("../services/OAuthService"));
11
11
  const jsonwebtoken_1 = require("jsonwebtoken");
12
12
  /**
13
13
  * 用户登出
@@ -42,7 +42,7 @@ async function logout(req, res) {
42
42
  const decoded = (0, jsonwebtoken_1.decode)(accessToken);
43
43
  const sessionId = decoded?.sessionId;
44
44
  if (sessionId) {
45
- const oauthService = new oauthService_1.default();
45
+ const oauthService = new OAuthService_1.default();
46
46
  await oauthService.revokeSession(sessionId);
47
47
  }
48
48
  }
@@ -0,0 +1,8 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ /**
3
+ * GET /api/oauth/mock/avatar/:id
4
+ * mock 模式:无头像服务,直接返回 404
5
+ * 非 mock 模式:透传
6
+ */
7
+ export declare function avatarController(_req: Request, res: Response, next: NextFunction): void;
8
+ //# sourceMappingURL=avatarController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatarController.d.ts","sourceRoot":"","sources":["../../../../server/controllers/mock/avatarController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAGzD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAIhF"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.avatarController = avatarController;
4
+ const mockConfig_1 = require("../../mock/mockConfig");
5
+ /**
6
+ * GET /api/oauth/mock/avatar/:id
7
+ * mock 模式:无头像服务,直接返回 404
8
+ * 非 mock 模式:透传
9
+ */
10
+ function avatarController(_req, res, next) {
11
+ if (!(0, mockConfig_1.isMockMode)())
12
+ return next();
13
+ res.status(404).end();
14
+ }
15
+ //# sourceMappingURL=avatarController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"avatarController.js","sourceRoot":"","sources":["../../../../server/controllers/mock/avatarController.ts"],"names":[],"mappings":";;AAQA,4CAIC;AAXD,sDAAkD;AAElD;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,IAAa,EAAE,GAAa,EAAE,IAAkB;IAC/E,IAAI,CAAC,IAAA,uBAAU,GAAE;QAAE,OAAO,IAAI,EAAE,CAAA;IAEhC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAA;AACvB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ /**
3
+ * POST /api/oauth/mock/login
4
+ * mock 模式:直接签发 mock token,写入 HttpOnly Cookie,并返回用户信息
5
+ * 非 mock 模式:透传
6
+ */
7
+ export declare function loginController(_req: Request, res: Response, next: NextFunction): void | Response<any, Record<string, any>>;
8
+ //# sourceMappingURL=loginController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loginController.d.ts","sourceRoot":"","sources":["../../../../server/controllers/mock/loginController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAUzD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,6CAwB/E"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loginController = loginController;
4
+ const mockConfig_1 = require("../../mock/mockConfig");
5
+ const mockTokenUtils_1 = require("../../mock/mockTokenUtils");
6
+ const oauthTokenUtils_1 = require("../../utils/oauthTokenUtils");
7
+ /**
8
+ * POST /api/oauth/mock/login
9
+ * mock 模式:直接签发 mock token,写入 HttpOnly Cookie,并返回用户信息
10
+ * 非 mock 模式:透传
11
+ */
12
+ function loginController(_req, res, next) {
13
+ if (!(0, mockConfig_1.isMockMode)())
14
+ return next();
15
+ const { user } = (0, mockConfig_1.getMockConfig)();
16
+ const accessToken = (0, mockTokenUtils_1.generateMockAccessToken)(user);
17
+ const refreshToken = (0, mockTokenUtils_1.generateMockRefreshToken)(user);
18
+ (0, oauthTokenUtils_1.setOAuthTokenCookie)(res, accessToken, mockTokenUtils_1.MOCK_ACCESS_TOKEN_EXPIRES_IN, 'access');
19
+ (0, oauthTokenUtils_1.setOAuthTokenCookie)(res, refreshToken, mockTokenUtils_1.MOCK_REFRESH_TOKEN_EXPIRES_IN, 'refresh');
20
+ return res.json({
21
+ code: 'OK',
22
+ message: '登录成功',
23
+ data: {
24
+ isMock: true,
25
+ user: {
26
+ id: user.userId,
27
+ isVerified: user.isVerified,
28
+ roles: user.roles,
29
+ permissions: user.permissions
30
+ }
31
+ }
32
+ });
33
+ }
34
+ //# sourceMappingURL=loginController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loginController.js","sourceRoot":"","sources":["../../../../server/controllers/mock/loginController.ts"],"names":[],"mappings":";;AAeA,0CAwBC;AAtCD,sDAAiE;AACjE,8DAKkC;AAClC,iEAAiE;AAEjE;;;;GAIG;AACH,SAAgB,eAAe,CAAC,IAAa,EAAE,GAAa,EAAE,IAAkB;IAC9E,IAAI,CAAC,IAAA,uBAAU,GAAE;QAAE,OAAO,IAAI,EAAE,CAAA;IAEhC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAA,0BAAa,GAAE,CAAA;IAEhC,MAAM,WAAW,GAAG,IAAA,wCAAuB,EAAC,IAAI,CAAC,CAAA;IACjD,MAAM,YAAY,GAAG,IAAA,yCAAwB,EAAC,IAAI,CAAC,CAAA;IAEnD,IAAA,qCAAmB,EAAC,GAAG,EAAE,WAAW,EAAE,6CAA4B,EAAE,QAAQ,CAAC,CAAA;IAC7E,IAAA,qCAAmB,EAAC,GAAG,EAAE,YAAY,EAAE,8CAA6B,EAAE,SAAS,CAAC,CAAA;IAEhF,OAAO,GAAG,CAAC,IAAI,CAAC;QACd,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,MAAM;QACf,IAAI,EAAE;YACJ,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE;gBACJ,EAAE,EAAE,IAAI,CAAC,MAAM;gBACf,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;aAC9B;SACF;KACF,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ /**
3
+ * POST /api/oauth/mock/logout
4
+ * mock 模式:清除 mock token cookie
5
+ * 非 mock 模式:透传
6
+ */
7
+ export declare function logoutController(_req: Request, res: Response, next: NextFunction): void | Response<any, Record<string, any>>;
8
+ //# sourceMappingURL=logoutController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logoutController.d.ts","sourceRoot":"","sources":["../../../../server/controllers/mock/logoutController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAGzD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,6CAOhF"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logoutController = logoutController;
4
+ const mockConfig_1 = require("../../mock/mockConfig");
5
+ /**
6
+ * POST /api/oauth/mock/logout
7
+ * mock 模式:清除 mock token cookie
8
+ * 非 mock 模式:透传
9
+ */
10
+ function logoutController(_req, res, next) {
11
+ if (!(0, mockConfig_1.isMockMode)())
12
+ return next();
13
+ res.clearCookie('access_token');
14
+ res.clearCookie('refresh_token');
15
+ return res.json({ code: 'OK', message: '登出成功' });
16
+ }
17
+ //# sourceMappingURL=logoutController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logoutController.js","sourceRoot":"","sources":["../../../../server/controllers/mock/logoutController.ts"],"names":[],"mappings":";;AAQA,4CAOC;AAdD,sDAAkD;AAElD;;;;GAIG;AACH,SAAgB,gBAAgB,CAAC,IAAa,EAAE,GAAa,EAAE,IAAkB;IAC/E,IAAI,CAAC,IAAA,uBAAU,GAAE;QAAE,OAAO,IAAI,EAAE,CAAA;IAEhC,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC,CAAA;IAC/B,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,CAAA;IAEhC,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;AAClD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ /**
3
+ * GET /api/oauth/mock/nav/:target
4
+ * mock 模式:导航占位页,展示目标页面名称并提供回退按钮
5
+ * 非 mock 模式:透传
6
+ */
7
+ export declare function navController(req: Request, res: Response, next: NextFunction): void;
8
+ //# sourceMappingURL=navController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navController.d.ts","sourceRoot":"","sources":["../../../../server/controllers/mock/navController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAUzD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QA6E5E"}
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.navController = navController;
4
+ const mockConfig_1 = require("../../mock/mockConfig");
5
+ const NAV_LABELS = {
6
+ home: '首页',
7
+ site: '站点管理',
8
+ user: '用户中心',
9
+ feedback: '意见反馈'
10
+ };
11
+ /**
12
+ * GET /api/oauth/mock/nav/:target
13
+ * mock 模式:导航占位页,展示目标页面名称并提供回退按钮
14
+ * 非 mock 模式:透传
15
+ */
16
+ function navController(req, res, next) {
17
+ if (!(0, mockConfig_1.isMockMode)())
18
+ return next();
19
+ const target = req.params['target'];
20
+ const label = NAV_LABELS[target] || target;
21
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
22
+ res.send(`<!DOCTYPE html>
23
+ <html lang="zh-CN">
24
+ <head>
25
+ <meta charset="UTF-8" />
26
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
27
+ <title>[Mock] ${label}</title>
28
+ <style>
29
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
30
+ body {
31
+ min-height: 100vh;
32
+ display: flex;
33
+ align-items: center;
34
+ justify-content: center;
35
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
36
+ background: #f5f5f5;
37
+ color: #333;
38
+ }
39
+ .card {
40
+ background: #fff;
41
+ border-radius: 12px;
42
+ box-shadow: 0 4px 24px rgba(0,0,0,.08);
43
+ padding: 48px 56px;
44
+ text-align: center;
45
+ max-width: 420px;
46
+ width: 90%;
47
+ }
48
+ .badge {
49
+ display: inline-block;
50
+ background: #fff3cd;
51
+ color: #856404;
52
+ font-size: 12px;
53
+ font-weight: 600;
54
+ letter-spacing: .5px;
55
+ padding: 3px 10px;
56
+ border-radius: 99px;
57
+ margin-bottom: 20px;
58
+ }
59
+ h1 {
60
+ font-size: 24px;
61
+ font-weight: 700;
62
+ margin-bottom: 8px;
63
+ }
64
+ p {
65
+ font-size: 14px;
66
+ color: #888;
67
+ margin-bottom: 32px;
68
+ line-height: 1.6;
69
+ }
70
+ button {
71
+ background: #333;
72
+ color: #fff;
73
+ border: none;
74
+ border-radius: 8px;
75
+ padding: 10px 28px;
76
+ font-size: 14px;
77
+ cursor: pointer;
78
+ transition: background .15s;
79
+ }
80
+ button:hover { background: #555; }
81
+ </style>
82
+ </head>
83
+ <body>
84
+ <div class="card">
85
+ <span class="badge">MOCK</span>
86
+ <h1>${label}</h1>
87
+ <p>当前处于 Mock 模式,此页面为占位页。<br/>真实环境中将跳转到 OAuth 服务的「${label}」页面。</p>
88
+ <button onclick="history.back()">返回上一页</button>
89
+ </div>
90
+ </body>
91
+ </html>`);
92
+ }
93
+ //# sourceMappingURL=navController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navController.js","sourceRoot":"","sources":["../../../../server/controllers/mock/navController.ts"],"names":[],"mappings":";;AAeA,sCA6EC;AA3FD,sDAAkD;AAElD,MAAM,UAAU,GAA2B;IACzC,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,MAAM;CACjB,CAAA;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC3E,IAAI,CAAC,IAAA,uBAAU,GAAE;QAAE,OAAO,IAAI,EAAE,CAAA;IAEhC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAW,CAAA;IAC7C,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,MAAM,CAAA;IAE1C,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,0BAA0B,CAAC,CAAA;IACzD,GAAG,CAAC,IAAI,CAAC;;;;;kBAKO,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA2Db,KAAK;uDACwC,KAAK;;;;QAIpD,CAAC,CAAA;AACT,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { NextFunction, Request, Response } from 'express';
2
+ /**
3
+ * PUT /token
4
+ * mock 模式:验证 mock token 并返回用户信息,响应中包含 isMock: true
5
+ * 非 mock 模式:透传到真实的 tokenRefreshController
6
+ */
7
+ export declare function tokenController(req: Request, res: Response, next: NextFunction): void | Response<any, Record<string, any>>;
8
+ //# sourceMappingURL=tokenController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenController.d.ts","sourceRoot":"","sources":["../../../../server/controllers/mock/tokenController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAsBzD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,6CAoE9E"}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tokenController = tokenController;
4
+ const mockConfig_1 = require("../../mock/mockConfig");
5
+ const mockTokenUtils_1 = require("../../mock/mockTokenUtils");
6
+ const oauthTokenUtils_1 = require("../../utils/oauthTokenUtils");
7
+ function parseCookies(cookieString) {
8
+ const cookies = {};
9
+ if (!cookieString)
10
+ return cookies;
11
+ cookieString.split(';').forEach(cookie => {
12
+ const [name, value] = cookie.split('=');
13
+ if (name && value) {
14
+ cookies[name.trim()] = value.trim();
15
+ }
16
+ });
17
+ return cookies;
18
+ }
19
+ /**
20
+ * PUT /token
21
+ * mock 模式:验证 mock token 并返回用户信息,响应中包含 isMock: true
22
+ * 非 mock 模式:透传到真实的 tokenRefreshController
23
+ */
24
+ function tokenController(req, res, next) {
25
+ if (!(0, mockConfig_1.isMockMode)())
26
+ return next();
27
+ const { user } = (0, mockConfig_1.getMockConfig)();
28
+ const cookies = parseCookies(req.headers.cookie);
29
+ const accessTokenRaw = cookies.access_token || '';
30
+ const refreshTokenRaw = cookies.refresh_token || '';
31
+ // 先验证 access_token
32
+ if (accessTokenRaw && (0, mockTokenUtils_1.isMockToken)(accessTokenRaw)) {
33
+ try {
34
+ const claims = (0, mockTokenUtils_1.verifyMockToken)(accessTokenRaw);
35
+ if (claims.sub) {
36
+ return res.json({
37
+ code: 'OK',
38
+ message: 'Token 仍然有效',
39
+ data: {
40
+ isMock: true,
41
+ user: {
42
+ id: claims.sub,
43
+ isVerified: claims.isVerified ?? user.isVerified,
44
+ roles: claims.roles ?? user.roles,
45
+ permissions: claims.permissions ?? user.permissions
46
+ }
47
+ }
48
+ });
49
+ }
50
+ }
51
+ catch {
52
+ // access_token 过期,继续尝试 refresh_token
53
+ }
54
+ }
55
+ // 使用 refresh_token 重签 access_token
56
+ if (refreshTokenRaw && (0, mockTokenUtils_1.isMockToken)(refreshTokenRaw)) {
57
+ try {
58
+ (0, mockTokenUtils_1.verifyMockToken)(refreshTokenRaw);
59
+ const newAccessToken = (0, mockTokenUtils_1.generateMockAccessToken)(user);
60
+ (0, oauthTokenUtils_1.setOAuthTokenCookie)(res, newAccessToken, mockTokenUtils_1.MOCK_ACCESS_TOKEN_EXPIRES_IN, 'access');
61
+ return res.json({
62
+ code: 'OK',
63
+ message: 'Token 刷新成功',
64
+ data: {
65
+ isMock: true,
66
+ user: {
67
+ id: user.userId,
68
+ isVerified: user.isVerified,
69
+ roles: user.roles,
70
+ permissions: user.permissions
71
+ }
72
+ }
73
+ });
74
+ }
75
+ catch {
76
+ // refresh_token 也过期了
77
+ }
78
+ }
79
+ // 未登录
80
+ return res.json({
81
+ code: 'OK',
82
+ message: '未登录',
83
+ data: {
84
+ isMock: true,
85
+ user: null
86
+ }
87
+ });
88
+ }
89
+ //# sourceMappingURL=tokenController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenController.js","sourceRoot":"","sources":["../../../../server/controllers/mock/tokenController.ts"],"names":[],"mappings":"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"}
@@ -11,7 +11,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.default = oauthCallbackController;
14
- const oauthService_1 = __importDefault(require("../services/oauthService"));
14
+ const OAuthService_1 = __importDefault(require("../services/OAuthService"));
15
15
  const tokenModel_1 = require("../models/tokenModel");
16
16
  const config_1 = require("../utils/config");
17
17
  const oauthTokenUtils_1 = require("../utils/oauthTokenUtils");
@@ -30,7 +30,7 @@ async function exchangeCodeForToken(code, codeVerifier) {
30
30
  // 使用配置中的 redirectUri
31
31
  const oauthConfig = (0, config_1.getOAuthConfig)();
32
32
  const uri = oauthConfig.redirectUri;
33
- const oauthService = new oauthService_1.default();
33
+ const oauthService = new OAuthService_1.default();
34
34
  const data = await oauthService.exchangeCode('authorization_code', code, uri, verifier);
35
35
  // 验证响应数据的完整性
36
36
  if (!data || !data.accessToken || !data.tokenType || typeof data.expiresIn !== 'number') {
@@ -10,7 +10,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.default = tokenRefreshController;
13
- const oauthService_1 = __importDefault(require("../services/oauthService"));
13
+ const OAuthService_1 = __importDefault(require("../services/OAuthService"));
14
14
  const oauthTokenUtils_1 = require("../utils/oauthTokenUtils");
15
15
  const tokenModel_1 = require("../models/tokenModel");
16
16
  const config_1 = require("../utils/config");
@@ -55,7 +55,7 @@ async function tokenRefreshController(req, res) {
55
55
  // 如果有有效的 refreshToken,进行刷新
56
56
  if (refreshToken) {
57
57
  // 使用 OAuthService 调用 OAuth API
58
- const oauthService = new oauthService_1.default();
58
+ const oauthService = new OAuthService_1.default();
59
59
  const tokenData = await oauthService.refreshAccessToken(refreshToken);
60
60
  // 使用公用的 token 设置函数
61
61
  // 设置新的 accessToken
@@ -2,7 +2,7 @@
2
2
  * Sumor OAuth 暴露接口
3
3
  * 导出所需的中间件、路由和服务供客户端使用
4
4
  */
5
- import OAuthService from './services/oauthService';
5
+ import OAuthService from './services/OAuthService';
6
6
  import oauthRoutes from './routes';
7
7
  import { loadJwtUserMiddleware } from './middlewares/loadJwtUserMiddleware';
8
8
  /**
@@ -8,8 +8,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
8
8
  };
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.oauthRoutes = exports.loadJwtUserMiddleware = exports.OAuthService = void 0;
11
- const oauthService_1 = __importDefault(require("./services/oauthService"));
12
- exports.OAuthService = oauthService_1.default;
11
+ const OAuthService_1 = __importDefault(require("./services/OAuthService"));
12
+ exports.OAuthService = OAuthService_1.default;
13
13
  const routes_1 = __importDefault(require("./routes"));
14
14
  exports.oauthRoutes = routes_1.default;
15
15
  const loadJwtUserMiddleware_1 = require("./middlewares/loadJwtUserMiddleware");
@@ -21,14 +21,12 @@ export interface MockConfig {
21
21
  }
22
22
  /**
23
23
  * 判断是否启用了 Mock 模式
24
+ * 每次调用都从 process.env 读取,确保 dotenv 初始化后能正确感知
24
25
  */
25
26
  export declare function isMockMode(): boolean;
26
27
  /**
27
28
  * 获取 Mock 配置
29
+ * 每次调用都从 process.env 读取,避免 dotenv 未加载时缓存错误值
28
30
  */
29
31
  export declare function getMockConfig(): MockConfig;
30
- /**
31
- * 重置缓存(测试用)
32
- */
33
- export declare function resetMockConfigCache(): void;
34
32
  //# sourceMappingURL=mockConfig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mockConfig.d.ts","sourceRoot":"","sources":["../../../server/mock/mockConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,cAAc,CAAA;CACrB;AAID;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAa1C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
1
+ {"version":3,"file":"mockConfig.d.ts","sourceRoot":"","sources":["../../../server/mock/mockConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,cAAc,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAU1C"}
@@ -13,35 +13,26 @@
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.isMockMode = isMockMode;
15
15
  exports.getMockConfig = getMockConfig;
16
- exports.resetMockConfigCache = resetMockConfigCache;
17
- let cachedMockConfig = null;
18
16
  /**
19
17
  * 判断是否启用了 Mock 模式
18
+ * 每次调用都从 process.env 读取,确保 dotenv 初始化后能正确感知
20
19
  */
21
20
  function isMockMode() {
22
21
  return process.env.OAUTH_MOCK === 'true';
23
22
  }
24
23
  /**
25
24
  * 获取 Mock 配置
25
+ * 每次调用都从 process.env 读取,避免 dotenv 未加载时缓存错误值
26
26
  */
27
27
  function getMockConfig() {
28
- if (!cachedMockConfig) {
29
- cachedMockConfig = {
30
- enabled: isMockMode(),
31
- user: {
32
- userId: process.env.OAUTH_MOCK_USER_ID || 'mock-user-001',
33
- roles: process.env.OAUTH_MOCK_USER_ROLES || 'admin',
34
- permissions: process.env.OAUTH_MOCK_USER_PERMISSIONS || '',
35
- isVerified: parseInt(process.env.OAUTH_MOCK_USER_IS_VERIFIED || '1', 10)
36
- }
37
- };
38
- }
39
- return cachedMockConfig;
40
- }
41
- /**
42
- * 重置缓存(测试用)
43
- */
44
- function resetMockConfigCache() {
45
- cachedMockConfig = null;
28
+ return {
29
+ enabled: isMockMode(),
30
+ user: {
31
+ userId: process.env.OAUTH_MOCK_USER_ID || 'mock-user-001',
32
+ roles: process.env.OAUTH_MOCK_USER_ROLES || 'admin',
33
+ permissions: process.env.OAUTH_MOCK_USER_PERMISSIONS || '',
34
+ isVerified: parseInt(process.env.OAUTH_MOCK_USER_IS_VERIFIED || '1', 10)
35
+ }
36
+ };
46
37
  }
47
38
  //# sourceMappingURL=mockConfig.js.map