@dangao/bun-server 1.7.1 → 1.8.0

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 (116) hide show
  1. package/README.md +129 -21
  2. package/dist/di/decorators.d.ts +37 -0
  3. package/dist/di/decorators.d.ts.map +1 -1
  4. package/dist/di/index.d.ts +1 -1
  5. package/dist/di/index.d.ts.map +1 -1
  6. package/dist/di/module-registry.d.ts +17 -0
  7. package/dist/di/module-registry.d.ts.map +1 -1
  8. package/dist/events/decorators.d.ts +52 -0
  9. package/dist/events/decorators.d.ts.map +1 -0
  10. package/dist/events/event-module.d.ts +97 -0
  11. package/dist/events/event-module.d.ts.map +1 -0
  12. package/dist/events/index.d.ts +5 -0
  13. package/dist/events/index.d.ts.map +1 -0
  14. package/dist/events/service.d.ts +76 -0
  15. package/dist/events/service.d.ts.map +1 -0
  16. package/dist/events/types.d.ts +184 -0
  17. package/dist/events/types.d.ts.map +1 -0
  18. package/dist/index.d.ts +5 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1511 -11
  21. package/dist/security/filter.d.ts +23 -0
  22. package/dist/security/filter.d.ts.map +1 -1
  23. package/dist/security/guards/builtin/auth-guard.d.ts +44 -0
  24. package/dist/security/guards/builtin/auth-guard.d.ts.map +1 -0
  25. package/dist/security/guards/builtin/index.d.ts +3 -0
  26. package/dist/security/guards/builtin/index.d.ts.map +1 -0
  27. package/dist/security/guards/builtin/roles-guard.d.ts +66 -0
  28. package/dist/security/guards/builtin/roles-guard.d.ts.map +1 -0
  29. package/dist/security/guards/decorators.d.ts +50 -0
  30. package/dist/security/guards/decorators.d.ts.map +1 -0
  31. package/dist/security/guards/execution-context.d.ts +56 -0
  32. package/dist/security/guards/execution-context.d.ts.map +1 -0
  33. package/dist/security/guards/guard-registry.d.ts +67 -0
  34. package/dist/security/guards/guard-registry.d.ts.map +1 -0
  35. package/dist/security/guards/index.d.ts +7 -0
  36. package/dist/security/guards/index.d.ts.map +1 -0
  37. package/dist/security/guards/reflector.d.ts +57 -0
  38. package/dist/security/guards/reflector.d.ts.map +1 -0
  39. package/dist/security/guards/types.d.ts +126 -0
  40. package/dist/security/guards/types.d.ts.map +1 -0
  41. package/dist/security/index.d.ts +1 -0
  42. package/dist/security/index.d.ts.map +1 -1
  43. package/dist/security/security-module.d.ts +20 -0
  44. package/dist/security/security-module.d.ts.map +1 -1
  45. package/dist/validation/class-validator.d.ts +108 -0
  46. package/dist/validation/class-validator.d.ts.map +1 -0
  47. package/dist/validation/custom-validator.d.ts +130 -0
  48. package/dist/validation/custom-validator.d.ts.map +1 -0
  49. package/dist/validation/errors.d.ts +22 -2
  50. package/dist/validation/errors.d.ts.map +1 -1
  51. package/dist/validation/index.d.ts +7 -1
  52. package/dist/validation/index.d.ts.map +1 -1
  53. package/dist/validation/rules/array.d.ts +33 -0
  54. package/dist/validation/rules/array.d.ts.map +1 -0
  55. package/dist/validation/rules/common.d.ts +90 -0
  56. package/dist/validation/rules/common.d.ts.map +1 -0
  57. package/dist/validation/rules/conditional.d.ts +30 -0
  58. package/dist/validation/rules/conditional.d.ts.map +1 -0
  59. package/dist/validation/rules/index.d.ts +5 -0
  60. package/dist/validation/rules/index.d.ts.map +1 -0
  61. package/dist/validation/rules/object.d.ts +30 -0
  62. package/dist/validation/rules/object.d.ts.map +1 -0
  63. package/dist/validation/types.d.ts +52 -1
  64. package/dist/validation/types.d.ts.map +1 -1
  65. package/docs/events.md +494 -0
  66. package/docs/guards.md +376 -0
  67. package/docs/guide.md +309 -1
  68. package/docs/request-lifecycle.md +444 -0
  69. package/docs/validation.md +407 -0
  70. package/docs/zh/events.md +494 -0
  71. package/docs/zh/guards.md +376 -0
  72. package/docs/zh/guide.md +309 -1
  73. package/docs/zh/request-lifecycle.md +444 -0
  74. package/docs/zh/validation.md +407 -0
  75. package/package.json +1 -1
  76. package/src/di/decorators.ts +46 -0
  77. package/src/di/index.ts +10 -1
  78. package/src/di/module-registry.ts +39 -0
  79. package/src/events/decorators.ts +103 -0
  80. package/src/events/event-module.ts +272 -0
  81. package/src/events/index.ts +32 -0
  82. package/src/events/service.ts +352 -0
  83. package/src/events/types.ts +223 -0
  84. package/src/index.ts +133 -1
  85. package/src/security/filter.ts +88 -8
  86. package/src/security/guards/builtin/auth-guard.ts +68 -0
  87. package/src/security/guards/builtin/index.ts +3 -0
  88. package/src/security/guards/builtin/roles-guard.ts +165 -0
  89. package/src/security/guards/decorators.ts +124 -0
  90. package/src/security/guards/execution-context.ts +152 -0
  91. package/src/security/guards/guard-registry.ts +164 -0
  92. package/src/security/guards/index.ts +7 -0
  93. package/src/security/guards/reflector.ts +99 -0
  94. package/src/security/guards/types.ts +144 -0
  95. package/src/security/index.ts +1 -0
  96. package/src/security/security-module.ts +72 -2
  97. package/src/validation/class-validator.ts +322 -0
  98. package/src/validation/custom-validator.ts +289 -0
  99. package/src/validation/errors.ts +50 -2
  100. package/src/validation/index.ts +103 -1
  101. package/src/validation/rules/array.ts +118 -0
  102. package/src/validation/rules/common.ts +286 -0
  103. package/src/validation/rules/conditional.ts +52 -0
  104. package/src/validation/rules/index.ts +51 -0
  105. package/src/validation/rules/object.ts +86 -0
  106. package/src/validation/types.ts +61 -1
  107. package/tests/di/global-module.test.ts +487 -0
  108. package/tests/events/event-decorators.test.ts +173 -0
  109. package/tests/events/event-emitter.test.ts +373 -0
  110. package/tests/events/event-module.test.ts +373 -0
  111. package/tests/security/guards/guards-integration.test.ts +371 -0
  112. package/tests/security/guards/guards.test.ts +775 -0
  113. package/tests/security/security-module.test.ts +2 -2
  114. package/tests/validation/class-validator.test.ts +349 -0
  115. package/tests/validation/custom-validator.test.ts +335 -0
  116. package/tests/validation/rules.test.ts +543 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * 事件监听器接口
3
+ * @template T - 事件负载类型
4
+ */
5
+ export interface EventListener<T = unknown> {
6
+ (payload: T): void | Promise<void>;
7
+ }
8
+
9
+ /**
10
+ * 事件元数据
11
+ */
12
+ export interface EventMetadata {
13
+ /**
14
+ * 事件名称或标识符
15
+ */
16
+ event: string | symbol;
17
+
18
+ /**
19
+ * 是否异步处理
20
+ * @default false
21
+ */
22
+ async?: boolean;
23
+
24
+ /**
25
+ * 监听器优先级(数值越大优先级越高)
26
+ * @default 0
27
+ */
28
+ priority?: number;
29
+ }
30
+
31
+ /**
32
+ * 已注册的监听器信息
33
+ */
34
+ export interface RegisteredListener<T = unknown> {
35
+ /**
36
+ * 监听器函数
37
+ */
38
+ listener: EventListener<T>;
39
+
40
+ /**
41
+ * 是否一次性监听
42
+ */
43
+ once: boolean;
44
+
45
+ /**
46
+ * 优先级
47
+ */
48
+ priority: number;
49
+
50
+ /**
51
+ * 是否异步处理
52
+ */
53
+ async: boolean;
54
+ }
55
+
56
+ /**
57
+ * EventEmitter 服务接口
58
+ */
59
+ export interface EventEmitter {
60
+ /**
61
+ * 发布事件(同步触发所有监听器,不等待异步监听器完成)
62
+ * @param event - 事件名称或标识符
63
+ * @param payload - 事件负载
64
+ */
65
+ emit<T>(event: string | symbol, payload: T): void;
66
+
67
+ /**
68
+ * 异步发布事件(等待所有监听器完成)
69
+ * @param event - 事件名称或标识符
70
+ * @param payload - 事件负载
71
+ */
72
+ emitAsync<T>(event: string | symbol, payload: T): Promise<void>;
73
+
74
+ /**
75
+ * 订阅事件
76
+ * @param event - 事件名称或标识符
77
+ * @param listener - 监听器函数
78
+ * @param options - 监听选项
79
+ * @returns 取消订阅函数
80
+ */
81
+ on<T>(
82
+ event: string | symbol,
83
+ listener: EventListener<T>,
84
+ options?: ListenerOptions,
85
+ ): () => void;
86
+
87
+ /**
88
+ * 一次性订阅
89
+ * @param event - 事件名称或标识符
90
+ * @param listener - 监听器函数
91
+ * @param options - 监听选项
92
+ * @returns 取消订阅函数
93
+ */
94
+ once<T>(
95
+ event: string | symbol,
96
+ listener: EventListener<T>,
97
+ options?: ListenerOptions,
98
+ ): () => void;
99
+
100
+ /**
101
+ * 取消订阅
102
+ * @param event - 事件名称或标识符
103
+ * @param listener - 监听器函数
104
+ */
105
+ off<T>(event: string | symbol, listener: EventListener<T>): void;
106
+
107
+ /**
108
+ * 移除指定事件的所有监听器,或移除所有事件的所有监听器
109
+ * @param event - 事件名称或标识符(可选)
110
+ */
111
+ removeAllListeners(event?: string | symbol): void;
112
+
113
+ /**
114
+ * 获取指定事件的监听器数量
115
+ * @param event - 事件名称或标识符
116
+ */
117
+ listenerCount(event: string | symbol): number;
118
+
119
+ /**
120
+ * 获取所有已注册的事件名称
121
+ */
122
+ eventNames(): (string | symbol)[];
123
+ }
124
+
125
+ /**
126
+ * 监听器选项
127
+ */
128
+ export interface ListenerOptions {
129
+ /**
130
+ * 优先级(数值越大优先级越高)
131
+ * @default 0
132
+ */
133
+ priority?: number;
134
+
135
+ /**
136
+ * 是否异步处理
137
+ * @default false
138
+ */
139
+ async?: boolean;
140
+ }
141
+
142
+ /**
143
+ * EventModule 配置选项
144
+ */
145
+ export interface EventModuleOptions {
146
+ /**
147
+ * 是否启用通配符事件(如 'user.*')
148
+ * @default false
149
+ */
150
+ wildcard?: boolean;
151
+
152
+ /**
153
+ * 通配符分隔符
154
+ * @default '.'
155
+ */
156
+ delimiter?: string;
157
+
158
+ /**
159
+ * 全局事件前缀
160
+ */
161
+ globalPrefix?: string;
162
+
163
+ /**
164
+ * 最大监听器数量(防止内存泄漏)
165
+ * @default 10
166
+ */
167
+ maxListeners?: number;
168
+
169
+ /**
170
+ * 错误处理函数
171
+ * @param error - 错误对象
172
+ * @param event - 事件名称
173
+ * @param payload - 事件负载
174
+ */
175
+ onError?: (error: Error, event: string | symbol, payload: unknown) => void;
176
+ }
177
+
178
+ /**
179
+ * 装饰器方法元数据
180
+ */
181
+ export interface OnEventMethodMetadata {
182
+ /**
183
+ * 方法名
184
+ */
185
+ methodName: string;
186
+
187
+ /**
188
+ * 事件名称或标识符
189
+ */
190
+ event: string | symbol;
191
+
192
+ /**
193
+ * 是否异步处理
194
+ */
195
+ async: boolean;
196
+
197
+ /**
198
+ * 优先级
199
+ */
200
+ priority: number;
201
+ }
202
+
203
+ /**
204
+ * 事件服务 Token
205
+ */
206
+ export const EVENT_EMITTER_TOKEN = Symbol('@dangao/bun-server:events:emitter');
207
+
208
+ /**
209
+ * 事件模块选项 Token
210
+ */
211
+ export const EVENT_OPTIONS_TOKEN = Symbol('@dangao/bun-server:events:options');
212
+
213
+ /**
214
+ * OnEvent 装饰器元数据 Key
215
+ */
216
+ export const ON_EVENT_METADATA_KEY = Symbol('@dangao/bun-server:events:on-event');
217
+
218
+ /**
219
+ * 事件监听器类元数据 Key
220
+ */
221
+ export const EVENT_LISTENER_CLASS_METADATA_KEY = Symbol(
222
+ '@dangao/bun-server:events:listener-class',
223
+ );
package/src/index.ts CHANGED
@@ -25,7 +25,7 @@ export type {
25
25
  ControllerMetadata,
26
26
  } from './controller';
27
27
  export { Container } from './di/container';
28
- export { Injectable, Inject } from './di/decorators';
28
+ export { Injectable, Inject, Global, isGlobalModule, GLOBAL_MODULE_METADATA_KEY } from './di/decorators';
29
29
  export { Lifecycle, type ProviderConfig, type DependencyMetadata } from './di/types';
30
30
  export {
31
31
  Module,
@@ -71,15 +71,97 @@ export {
71
71
  type RateLimitOptions,
72
72
  type RateLimitStore,
73
73
  } from './middleware/builtin';
74
+ // Validation 模块
74
75
  export {
76
+ // 基础装饰器
75
77
  Validate,
76
78
  IsString,
77
79
  IsNumber,
78
80
  IsEmail,
79
81
  IsOptional,
80
82
  MinLength,
83
+ getValidationMetadata,
84
+ // 类型
85
+ type ValidationRuleDefinition,
86
+ type ValidationMetadata,
87
+ type ClassValidationMetadata,
88
+ type ValidationOptions,
89
+ // 验证器
90
+ validateParameters,
91
+ // 错误处理
81
92
  ValidationError,
82
93
  type ValidationIssue,
94
+ // 对象规则
95
+ IsObject,
96
+ IsNotEmpty,
97
+ IsNotEmptyObject,
98
+ ValidateNested,
99
+ type ObjectRuleOptions,
100
+ type ValidateNestedOptions,
101
+ // 数组规则
102
+ IsArray,
103
+ ArrayMinSize,
104
+ ArrayMaxSize,
105
+ ArrayUnique,
106
+ ArrayContains,
107
+ ArrayNotContains,
108
+ ArrayNotEmpty,
109
+ type ArrayRuleOptions,
110
+ // 通用规则
111
+ IsBoolean,
112
+ IsInt,
113
+ IsPositive,
114
+ IsNegative,
115
+ Min,
116
+ Max,
117
+ IsDate,
118
+ IsUUID,
119
+ Length,
120
+ MaxLength,
121
+ Matches,
122
+ IsIn,
123
+ IsNotIn,
124
+ IsUrl,
125
+ IsJSON,
126
+ Equals,
127
+ NotEquals,
128
+ IsDefined,
129
+ IsAlphanumeric,
130
+ IsAlpha,
131
+ IsNumberString,
132
+ type RuleOptions,
133
+ type UUIDVersion,
134
+ // 条件和转换规则
135
+ ValidateIf,
136
+ Transform,
137
+ type ConditionalRuleOptions,
138
+ // 自定义验证器
139
+ createCustomValidator,
140
+ createSimpleValidator,
141
+ createRegexValidator,
142
+ IsPhoneNumber,
143
+ IsIdCard,
144
+ IsIPv4,
145
+ IsPort,
146
+ IsPostalCode,
147
+ IsCreditCard,
148
+ IsHexColor,
149
+ IsMacAddress,
150
+ IsSemVer,
151
+ IsDivisibleBy,
152
+ IsBetween,
153
+ Contains,
154
+ NotContains,
155
+ type CustomValidatorOptions,
156
+ // 类级别验证
157
+ ValidateClass,
158
+ Property,
159
+ NestedProperty,
160
+ ArrayNestedProperty,
161
+ validateObject,
162
+ validateObjectSync,
163
+ getClassValidationMetadata,
164
+ isValidateClass,
83
165
  } from './validation';
84
166
  export {
85
167
  HttpException,
@@ -136,6 +218,8 @@ export {
136
218
  JwtAuthenticationProvider,
137
219
  OAuth2AuthenticationProvider,
138
220
  createSecurityFilter,
221
+ getGuardRegistry,
222
+ registerReflector,
139
223
  type SecurityModuleConfig,
140
224
  type SecurityConfig,
141
225
  type SecurityContext,
@@ -146,6 +230,32 @@ export {
146
230
  type Credentials,
147
231
  type AccessDecisionManager,
148
232
  } from './security';
233
+ // Guards 子模块
234
+ export {
235
+ UseGuards,
236
+ Roles,
237
+ getGuardsMetadata,
238
+ getRolesMetadata,
239
+ AuthGuard,
240
+ OptionalAuthGuard,
241
+ RolesGuard,
242
+ createRolesGuard,
243
+ GuardRegistry,
244
+ ExecutionContextImpl,
245
+ Reflector,
246
+ GUARDS_METADATA_KEY,
247
+ GUARD_REGISTRY_TOKEN,
248
+ ROLES_METADATA_KEY,
249
+ REFLECTOR_TOKEN,
250
+ type CanActivate,
251
+ type ExecutionContext,
252
+ type HttpArgumentsHost,
253
+ type WsArgumentsHost,
254
+ type GuardType,
255
+ type GuardMetadata,
256
+ type GuardOptions,
257
+ type RolesGuardOptions,
258
+ } from './security/guards';
149
259
  export {
150
260
  ConfigModule,
151
261
  ConfigService,
@@ -394,4 +504,26 @@ export {
394
504
  type ServiceInstanceHealth,
395
505
  type MonitoringOptions,
396
506
  } from './microservice';
507
+ // Events 模块
508
+ export {
509
+ EventModule,
510
+ EventEmitterService,
511
+ EventListenerScanner,
512
+ OnEvent,
513
+ getOnEventMetadata,
514
+ isEventListenerClass,
515
+ EVENT_EMITTER_TOKEN,
516
+ EVENT_OPTIONS_TOKEN,
517
+ EVENT_LISTENER_SCANNER_TOKEN,
518
+ ON_EVENT_METADATA_KEY,
519
+ EVENT_LISTENER_CLASS_METADATA_KEY,
520
+ type EventEmitter,
521
+ type EventListener,
522
+ type EventMetadata,
523
+ type EventModuleOptions,
524
+ type ListenerOptions,
525
+ type OnEventMethodMetadata,
526
+ type OnEventOptions,
527
+ type RegisteredListener,
528
+ } from './events';
397
529
 
@@ -1,5 +1,6 @@
1
1
  import type { Context } from '../core/context';
2
2
  import type { Middleware } from '../middleware';
3
+ import type { Container } from '../di/container';
3
4
  import { SecurityContextHolder } from './context';
4
5
  import { AuthenticationManager } from './authentication-manager';
5
6
  import { RoleBasedAccessDecisionManager } from './access-decision-manager';
@@ -10,6 +11,10 @@ import {
10
11
  } from '../error/http-exception';
11
12
  import { ErrorCode } from '../error/error-codes';
12
13
  import { requiresAuth, getAuthMetadata } from '../auth/decorators';
14
+ import { GuardRegistry } from './guards/guard-registry';
15
+ import { ExecutionContextImpl } from './guards/execution-context';
16
+ import { Reflector, REFLECTOR_TOKEN } from './guards/reflector';
17
+ import { GUARD_REGISTRY_TOKEN } from './guards/types';
13
18
 
14
19
  /**
15
20
  * 安全过滤器配置
@@ -27,6 +32,14 @@ export interface SecurityFilterConfig extends SecurityConfig {
27
32
  * 令牌提取函数
28
33
  */
29
34
  extractToken?: (ctx: Context) => string | null;
35
+ /**
36
+ * DI 容器(用于解析守卫)
37
+ */
38
+ container?: Container;
39
+ /**
40
+ * 守卫注册表
41
+ */
42
+ guardRegistry?: GuardRegistry;
30
43
  }
31
44
 
32
45
  /**
@@ -39,8 +52,30 @@ export function createSecurityFilter(config: SecurityFilterConfig): Middleware {
39
52
  excludePaths = [],
40
53
  defaultAuthRequired = true,
41
54
  extractToken,
55
+ container: initialContainer,
56
+ guardRegistry,
42
57
  } = config;
43
58
 
59
+ // 创建或使用传入的守卫注册表
60
+ const registry = guardRegistry || new GuardRegistry();
61
+
62
+ // 延迟获取容器的函数
63
+ let cachedContainer: Container | null = initialContainer || null;
64
+ const getContainer = (): Container | null => {
65
+ if (cachedContainer) {
66
+ return cachedContainer;
67
+ }
68
+ // 尝试从 ControllerRegistry 获取容器
69
+ try {
70
+ // 动态导入避免循环依赖
71
+ const { ControllerRegistry } = require('../controller/controller');
72
+ cachedContainer = ControllerRegistry.getInstance().getContainer();
73
+ return cachedContainer;
74
+ } catch {
75
+ return null;
76
+ }
77
+ };
78
+
44
79
  return async (ctx: Context, next) => {
45
80
  return SecurityContextHolder.runWithContext(async () => {
46
81
  // 检查是否在排除列表中
@@ -74,6 +109,14 @@ export function createSecurityFilter(config: SecurityFilterConfig): Middleware {
74
109
  }
75
110
  }
76
111
 
112
+ // 将安全上下文附加到 Context(在守卫执行前)
113
+ (ctx as any).security = securityContext;
114
+ (ctx as any).auth = {
115
+ isAuthenticated: securityContext.isAuthenticated(),
116
+ user: securityContext.getPrincipal(),
117
+ payload: (securityContext.authentication?.details as any),
118
+ };
119
+
77
120
  // 检查是否需要认证
78
121
  const handler = (ctx as any).routeHandler;
79
122
  if (handler) {
@@ -82,6 +125,23 @@ export function createSecurityFilter(config: SecurityFilterConfig): Middleware {
82
125
  (controllerClass && controllerClass.prototype) || controllerClass;
83
126
  const method = handler.method;
84
127
 
128
+ // 执行守卫链(在 @Auth 检查之前)
129
+ // Guards 在中间件之后、拦截器之前执行
130
+ const container = getContainer();
131
+ // 只有当 controllerClass 是一个有效的类(构造函数)时才执行守卫
132
+ // 测试中可能传入原型而不是类,这种情况跳过守卫执行
133
+ if (container && typeof controllerClass === 'function') {
134
+ const methodHandler = controllerTarget[method];
135
+ const executionContext = new ExecutionContextImpl(
136
+ ctx,
137
+ controllerClass,
138
+ method,
139
+ methodHandler || (() => {}),
140
+ );
141
+ await registry.executeGuards(executionContext, container);
142
+ }
143
+
144
+ // 传统的 @Auth 装饰器检查(向后兼容)
85
145
  if (requiresAuth(controllerTarget, method)) {
86
146
  const authentication = securityContext.authentication;
87
147
  if (!authentication || !authentication.authenticated) {
@@ -118,14 +178,6 @@ export function createSecurityFilter(config: SecurityFilterConfig): Middleware {
118
178
  );
119
179
  }
120
180
 
121
- // 将安全上下文附加到 Context
122
- (ctx as any).security = securityContext;
123
- (ctx as any).auth = {
124
- isAuthenticated: securityContext.isAuthenticated(),
125
- user: securityContext.getPrincipal(),
126
- payload: (securityContext.authentication?.details as any),
127
- };
128
-
129
181
  return await next();
130
182
  } finally {
131
183
  // 清理当前请求内的认证信息,防止泄漏到下一个请求
@@ -135,6 +187,34 @@ export function createSecurityFilter(config: SecurityFilterConfig): Middleware {
135
187
  };
136
188
  }
137
189
 
190
+ /**
191
+ * 获取守卫注册表
192
+ * @param container - DI 容器
193
+ * @returns 守卫注册表实例
194
+ */
195
+ export function getGuardRegistry(container: Container): GuardRegistry {
196
+ if (container.isRegistered(GUARD_REGISTRY_TOKEN)) {
197
+ return container.resolve<GuardRegistry>(GUARD_REGISTRY_TOKEN);
198
+ }
199
+ const registry = new GuardRegistry();
200
+ container.registerInstance(GUARD_REGISTRY_TOKEN, registry);
201
+ return registry;
202
+ }
203
+
204
+ /**
205
+ * 注册 Reflector 到 DI 容器
206
+ * @param container - DI 容器
207
+ * @returns Reflector 实例
208
+ */
209
+ export function registerReflector(container: Container): Reflector {
210
+ if (container.isRegistered(REFLECTOR_TOKEN)) {
211
+ return container.resolve<Reflector>(REFLECTOR_TOKEN);
212
+ }
213
+ const reflector = new Reflector();
214
+ container.registerInstance(REFLECTOR_TOKEN, reflector);
215
+ return reflector;
216
+ }
217
+
138
218
  /**
139
219
  * 从请求头提取令牌
140
220
  */
@@ -0,0 +1,68 @@
1
+ import { Injectable } from '../../../di/decorators';
2
+ import type { CanActivate, ExecutionContext } from '../types';
3
+ import { SecurityContextHolder } from '../../context';
4
+ import { UnauthorizedException } from '../../../error/http-exception';
5
+ import { ErrorCode } from '../../../error/error-codes';
6
+
7
+ /**
8
+ * 认证守卫
9
+ * 检查请求是否已认证
10
+ *
11
+ * @example
12
+ * @Controller('/api/users')
13
+ * @UseGuards(AuthGuard)
14
+ * class UserController {
15
+ * @GET('/profile')
16
+ * getProfile() {
17
+ * // 只有已认证的用户才能访问
18
+ * }
19
+ * }
20
+ */
21
+ @Injectable()
22
+ export class AuthGuard implements CanActivate {
23
+ /**
24
+ * 判断是否允许访问
25
+ * @param context - 执行上下文
26
+ * @returns 如果已认证则返回 true,否则抛出 UnauthorizedException
27
+ */
28
+ public canActivate(context: ExecutionContext): boolean {
29
+ const securityContext = SecurityContextHolder.getContext();
30
+
31
+ if (!securityContext.isAuthenticated()) {
32
+ throw new UnauthorizedException(
33
+ 'Authentication required',
34
+ undefined,
35
+ ErrorCode.AUTH_REQUIRED,
36
+ );
37
+ }
38
+
39
+ return true;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * 可选认证守卫
45
+ * 如果有 token 则验证,没有 token 也允许访问
46
+ *
47
+ * @example
48
+ * @GET('/public')
49
+ * @UseGuards(OptionalAuthGuard)
50
+ * publicEndpoint() {
51
+ * // 未认证也可以访问,但如果有 token 会被验证
52
+ * }
53
+ */
54
+ @Injectable()
55
+ export class OptionalAuthGuard implements CanActivate {
56
+ /**
57
+ * 判断是否允许访问
58
+ * 总是返回 true,但会检查认证状态
59
+ * @param context - 执行上下文
60
+ * @returns 总是返回 true
61
+ */
62
+ public canActivate(context: ExecutionContext): boolean {
63
+ // 可选认证:不强制要求认证,但如果有认证信息会被使用
64
+ // SecurityFilter 已经处理了 token 解析和认证
65
+ return true;
66
+ }
67
+ }
68
+
@@ -0,0 +1,3 @@
1
+ export { AuthGuard, OptionalAuthGuard } from './auth-guard';
2
+ export { RolesGuard, createRolesGuard, type RolesGuardOptions } from './roles-guard';
3
+