@longzai-intelligence-auth/express 0.0.2 → 0.0.6

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/dist/index.d.ts CHANGED
@@ -1,22 +1,268 @@
1
- export { mapDomainErrorToStatus } from "./core/error-mapper";
2
- export { createJwtVerifyMiddleware } from "./middlewares/jwt-verify.middleware";
3
- export type { JwtVerifyMiddlewareOptions } from "./middlewares/jwt-verify.middleware";
4
- export { createRbacMiddleware } from "./middlewares/rbac.middleware";
5
- export type { RbacMiddlewareOptions } from "./middlewares/rbac.middleware";
6
- export { createTenantMiddleware } from "./middlewares/tenant.middleware";
7
- export type { TenantMiddlewareOptions } from "./middlewares/tenant.middleware";
8
- export { createRateLimitMiddleware } from "./middlewares/rate-limit.middleware";
9
- export type { RateLimitMiddlewareOptions } from "./middlewares/rate-limit.middleware";
10
- export { createAuditMiddleware } from "./middlewares/audit.middleware";
11
- export type { AuditMiddlewareOptions } from "./middlewares/audit.middleware";
12
- export { createLoggerMiddleware } from "./middlewares/logger.middleware";
13
- export type { LoggerMiddlewareOptions } from "./middlewares/logger.middleware";
14
- export { createErrorHandlerMiddleware } from "./middlewares/error-handler.middleware";
15
- export type { ErrorHandlerMiddlewareOptions } from "./middlewares/error-handler.middleware";
16
- export { createBasicPreset } from "./presets/basic-preset";
17
- export type { BasicPresetOptions } from "./presets/basic-preset";
18
- export { createStandardPreset } from "./presets/standard-preset";
19
- export type { StandardPresetOptions } from "./presets/standard-preset";
20
- export { extractClientIp } from "./utils/extract-client-ip";
21
- export { extractUserAgent } from "./utils/extract-user-agent";
22
- export type { AuthRequest } from "./types/express-auth.types";
1
+ import { DomainError } from "@longzai-intelligence/error";
2
+ import { AccessTokenPayload, IdentityAuthBackend, LoggerService, RateLimiterPort, TokenVerifierPort } from "@longzai-intelligence-auth/core";
3
+ import { NextFunction, Request, RequestHandler, Response } from "express";
4
+
5
+ //#region src/core/error-mapper.d.ts
6
+ /**
7
+ * 根据 DomainError 类型映射 HTTP 状态码
8
+ *
9
+ * @param error - 需要映射的领域错误实例
10
+ *
11
+ * @returns 对应的 HTTP 状态码
12
+ */
13
+ declare function mapDomainErrorToStatus(error: DomainError): number;
14
+ //#endregion
15
+ //#region src/types/express-auth.types.d.ts
16
+ /**
17
+ * 扩展 Express Request,附加认证信息
18
+ */
19
+ type AuthRequest = {
20
+ /**
21
+ * 认证载荷
22
+ */
23
+ auth: AccessTokenPayload;
24
+ /**
25
+ * 租户 ID
26
+ */
27
+ tenantId: string;
28
+ /**
29
+ * 客户端 IP
30
+ */
31
+ clientIp?: string;
32
+ /**
33
+ * 限流剩余配额
34
+ */
35
+ rateLimitRemaining?: number;
36
+ } & Request;
37
+ /**
38
+ * JWT 验证中间件配置
39
+ */
40
+ type JwtVerifyMiddlewareOptions = {
41
+ /**
42
+ * 令牌验证器端口实例(用户注入)
43
+ */
44
+ verifier: TokenVerifierPort;
45
+ /**
46
+ * 默认租户 ID
47
+ */
48
+ defaultTenantId?: string;
49
+ };
50
+ /**
51
+ * RBAC 中间件配置
52
+ */
53
+ type RbacMiddlewareOptions = {
54
+ /**
55
+ * 令牌验证器端口实例(用户注入)
56
+ */
57
+ verifier: TokenVerifierPort;
58
+ /**
59
+ * 默认租户 ID
60
+ */
61
+ defaultTenantId?: string;
62
+ };
63
+ /**
64
+ * 租户中间件配置
65
+ */
66
+ type TenantMiddlewareOptions = {
67
+ /**
68
+ * 默认租户 ID
69
+ */
70
+ defaultTenantId?: string;
71
+ /**
72
+ * 认证后端适配器
73
+ */
74
+ adapter?: IdentityAuthBackend;
75
+ };
76
+ /**
77
+ * 限流中间件配置
78
+ */
79
+ type RateLimitMiddlewareOptions = {
80
+ /**
81
+ * 速率限制器端口实例(用户注入)
82
+ */
83
+ limiter: RateLimiterPort;
84
+ /**
85
+ * 日志服务
86
+ */
87
+ logger?: LoggerService;
88
+ /**
89
+ * 限流键生成器
90
+ */
91
+ keyGenerator?: (req: Request) => string;
92
+ };
93
+ /**
94
+ * 日志中间件配置
95
+ */
96
+ type LoggerMiddlewareOptions = {
97
+ /**
98
+ * 日志服务
99
+ */
100
+ logger: LoggerService;
101
+ };
102
+ /**
103
+ * 错误处理中间件配置
104
+ */
105
+ type ErrorHandlerMiddlewareOptions = {
106
+ /**
107
+ * 日志服务
108
+ */
109
+ logger?: LoggerService;
110
+ };
111
+ /**
112
+ * 基础预设配置
113
+ */
114
+ type BasicPresetOptions = {
115
+ /**
116
+ * 令牌验证器端口实例(用户注入)
117
+ */
118
+ tokenVerifier: TokenVerifierPort;
119
+ /**
120
+ * 默认租户 ID
121
+ */
122
+ defaultTenantId?: string;
123
+ /**
124
+ * 日志服务
125
+ */
126
+ logger?: LoggerService;
127
+ };
128
+ /**
129
+ * 标准预设配置
130
+ */
131
+ type StandardPresetOptions = {
132
+ /**
133
+ * 令牌验证器端口实例(用户注入)
134
+ */
135
+ tokenVerifier: TokenVerifierPort;
136
+ /**
137
+ * 速率限制器端口实例(用户注入)
138
+ */
139
+ rateLimiter: RateLimiterPort;
140
+ /**
141
+ * 默认租户 ID
142
+ */
143
+ defaultTenantId?: string;
144
+ /**
145
+ * 认证后端适配器
146
+ */
147
+ adapter: IdentityAuthBackend;
148
+ /**
149
+ * 日志服务
150
+ */
151
+ logger?: LoggerService;
152
+ };
153
+ //#endregion
154
+ //#region src/middlewares/jwt-verify.middleware.d.ts
155
+ /**
156
+ * 创建 JWT 验证中间件,从 Authorization Bearer 头提取令牌并验证
157
+ *
158
+ * @param options - 中间件配置选项
159
+ *
160
+ * @returns Express 中间件函数
161
+ */
162
+ declare function createJwtVerifyMiddleware(options: JwtVerifyMiddlewareOptions): (req: Request, _res: Response, next: NextFunction) => Promise<void>;
163
+ //#endregion
164
+ //#region src/middlewares/rbac.middleware.d.ts
165
+ /**
166
+ * 创建 RBAC 权限检查中间件,验证请求是否拥有指定权限
167
+ *
168
+ * @param options - 中间件配置选项
169
+ *
170
+ * @returns 返回一个函数,接收权限字符串并返回 Express 中间件
171
+ */
172
+ declare function createRbacMiddleware(options: RbacMiddlewareOptions): (permission: string) => (req: Request, _res: Response, next: NextFunction) => Promise<void>;
173
+ //#endregion
174
+ //#region src/middlewares/tenant.middleware.d.ts
175
+ /**
176
+ * 创建租户中间件,从 x-tenant-id 头提取租户 ID 并验证租户状态
177
+ *
178
+ * @param options - 中间件配置选项
179
+ *
180
+ * @returns Express 中间件函数
181
+ */
182
+ declare function createTenantMiddleware(options?: TenantMiddlewareOptions): (req: Request, _res: Response, next: NextFunction) => Promise<void>;
183
+ //#endregion
184
+ //#region src/middlewares/rate-limit.middleware.d.ts
185
+ /**
186
+ * 默认限流键生成器,从请求中提取客户端 IP
187
+ *
188
+ * @param req - Express 请求对象
189
+ *
190
+ * @returns 客户端 IP 地址
191
+ */
192
+ declare function defaultKeyGenerator(req: Request): string;
193
+ /**
194
+ * 创建限流中间件,基于 IP + 路径进行限流
195
+ *
196
+ * @param options - 中间件配置选项
197
+ *
198
+ * @returns Express 中间件函数
199
+ */
200
+ declare function createRateLimitMiddleware(options: RateLimitMiddlewareOptions): (req: Request, _res: Response, next: NextFunction) => Promise<void>;
201
+ //#endregion
202
+ //#region src/middlewares/logger.middleware.d.ts
203
+ /**
204
+ * 创建日志中间件,记录请求、响应和错误日志
205
+ *
206
+ * @param options - 中间件配置选项
207
+ *
208
+ * @returns Express 中间件函数
209
+ */
210
+ declare function createLoggerMiddleware(options: LoggerMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => void;
211
+ //#endregion
212
+ //#region src/middlewares/error-handler.middleware.d.ts
213
+ /**
214
+ * 创建错误处理中间件,捕获 DomainError 并映射为 HTTP 状态码响应
215
+ *
216
+ * @param options - 中间件配置选项
217
+ *
218
+ * @returns Express 错误处理中间件函数
219
+ */
220
+ declare function createErrorHandlerMiddleware(options?: ErrorHandlerMiddlewareOptions): (error: Error, req: Request, res: Response, _next: NextFunction) => void;
221
+ //#endregion
222
+ //#region src/presets/basic-preset.d.ts
223
+ /**
224
+ * 创建基础预设中间件集合,包含 JWT 验证和错误处理
225
+ *
226
+ * @param options - 预设配置选项
227
+ * @param options.tokenVerifier - 令牌验证器端口实例(用户注入)
228
+ * @param options.defaultTenantId - 默认租户 ID(可选)
229
+ * @param options.logger - 日志服务(可选)
230
+ * @returns Express 中间件数组
231
+ */
232
+ declare function createBasicPreset(options: BasicPresetOptions): RequestHandler[];
233
+ //#endregion
234
+ //#region src/presets/standard-preset.d.ts
235
+ /**
236
+ * 创建标准预设中间件集合,包含 JWT 验证、RBAC、租户、限流和错误处理
237
+ *
238
+ * @param options - 预设配置选项
239
+ * @param options.tokenVerifier - 令牌验证器端口实例(用户注入)
240
+ * @param options.rateLimiter - 速率限制器端口实例(用户注入)
241
+ * @param options.defaultTenantId - 默认租户 ID(可选)
242
+ * @param options.adapter - 认证后端适配器
243
+ * @param options.logger - 日志服务(可选)
244
+ * @returns Express 中间件数组
245
+ */
246
+ declare function createStandardPreset(options: StandardPresetOptions): RequestHandler[];
247
+ //#endregion
248
+ //#region src/utils/extract-client-ip.d.ts
249
+ /**
250
+ * 从请求中提取客户端 IP 地址
251
+ *
252
+ * @param req - Express 请求对象
253
+ *
254
+ * @returns 客户端 IP 地址,如果无法提取则返回 undefined
255
+ */
256
+ declare function extractClientIp(req: Request): string | undefined;
257
+ //#endregion
258
+ //#region src/utils/extract-user-agent.d.ts
259
+ /**
260
+ * 从请求中提取用户代理
261
+ *
262
+ * @param req - Express 请求对象
263
+ *
264
+ * @returns 用户代理字符串,如果不存在则返回 undefined
265
+ */
266
+ declare function extractUserAgent(req: Request): string | undefined;
267
+ //#endregion
268
+ export { type AuthRequest, type BasicPresetOptions, type ErrorHandlerMiddlewareOptions, type JwtVerifyMiddlewareOptions, type LoggerMiddlewareOptions, type RateLimitMiddlewareOptions, type RbacMiddlewareOptions, type StandardPresetOptions, type TenantMiddlewareOptions, createBasicPreset, createErrorHandlerMiddleware, createJwtVerifyMiddleware, createLoggerMiddleware, createRateLimitMiddleware, createRbacMiddleware, createStandardPreset, createTenantMiddleware, defaultKeyGenerator, extractClientIp, extractUserAgent, mapDomainErrorToStatus };
package/dist/index.js CHANGED
@@ -1,12 +1 @@
1
- export { mapDomainErrorToStatus } from "./core/error-mapper";
2
- export { createJwtVerifyMiddleware } from "./middlewares/jwt-verify.middleware";
3
- export { createRbacMiddleware } from "./middlewares/rbac.middleware";
4
- export { createTenantMiddleware } from "./middlewares/tenant.middleware";
5
- export { createRateLimitMiddleware } from "./middlewares/rate-limit.middleware";
6
- export { createAuditMiddleware } from "./middlewares/audit.middleware";
7
- export { createLoggerMiddleware } from "./middlewares/logger.middleware";
8
- export { createErrorHandlerMiddleware } from "./middlewares/error-handler.middleware";
9
- export { createBasicPreset } from "./presets/basic-preset";
10
- export { createStandardPreset } from "./presets/standard-preset";
11
- export { extractClientIp } from "./utils/extract-client-ip";
12
- export { extractUserAgent } from "./utils/extract-user-agent";
1
+ import{AuthenticationError as e,DomainError as t,DuplicateEntityError as n,isBusinessRuleError as r,isConcurrencyError as i,isEntityNotFoundError as a,isPermissionDeniedError as o,isValidationError as s}from"@longzai-intelligence/error";import{AccountDisabledError as c,InvalidCredentialsError as l,MfaRequiredError as u,RateLimitExceededError as d,TokenExpiredError as f,TokenInvalidError as p,TokenMissingError as m}from"@longzai-intelligence-auth/core";function h(t){return s(t)?400:t instanceof f||t instanceof p||t instanceof m||t instanceof u||t instanceof l||t instanceof c||t instanceof e?401:o(t)?403:a(t)?404:t instanceof n?409:t instanceof d?429:i(t)?409:r(t)?422:500}function g(e){let{verifier:t,defaultTenantId:n=`default`}=e;async function r(e,r,i){try{let r=e,a=e.headers.authorization,o=typeof a==`string`&&a.startsWith(`Bearer `)?a.slice(7):null;if(!o)throw new m;let s=await t.verifyAccessToken(o);if(!s.success||!s.payload)throw new p(s.error);let c=s.payload;r.auth=c,r.tenantId=c.tenantId??n,i()}catch(e){i(e)}}return r}function _(){return{extractRolesFromPayload(e){return{userId:e.sub,tenantId:e.tenantId,roles:e.roles??[]}},hasRole(e,t){return(e.roles??[]).includes(t)},hasAnyRole(e,t){let n=e.roles??[];return t.some(e=>n.includes(e))},hasPermission(e,t,n){let r=e.permissions??[],i=`${t}:${n}`;return!!(r.includes(i)||r.includes(`${t}:*`)||r.includes(`*:${n}`)||r.includes(`*:*`))},hasAnyPermission(e,t){let n=e.permissions??[];return t.some(e=>{let t=`${e.resource}:${e.action}`;return!!(n.includes(t)||n.includes(`${e.resource}:*`)||n.includes(`*:${e.action}`)||n.includes(`*:*`))})}}}function v(e){let{verifier:t,defaultTenantId:n=`default`}=e,r=_();function i(e){async function i(i,a,o){try{let a=i,s=i.headers.authorization,c=typeof s==`string`&&s.startsWith(`Bearer `)?s.slice(7):null;if(!c)throw new m;let l=await t.verifyAccessToken(c);if(!l.success||!l.payload)throw new p(l.error);let u=l.payload;a.auth=u,a.tenantId=u.tenantId??n;let[d,f]=e.split(`:`);if(!d||!f)throw Error(`无效的权限格式: ${e},应为 resource:action`);if(!r.hasPermission(u,d,f)){let{PermissionDeniedError:e}=await import(`@longzai-intelligence/error`);throw new e(d,f)}o()}catch(e){o(e)}}return i}return i}function y(e={}){let{defaultTenantId:t=`default`,adapter:n}=e;async function r(e,r,i){try{let r=e,a=e.headers[`x-tenant-id`]??t;if(r.tenantId=a,n&&a!==t&&!(await n.tenant.validateStatus(a)).valid){let{PermissionDeniedError:e}=await import(`@longzai-intelligence/error`);throw new e(`tenant`,`access`)}i()}catch(e){i(e)}}return r}function b(e){return e.headers[`x-forwarded-for`]?.split(`,`)[0]?.trim()??e.headers[`x-real-ip`]??e.ip??`unknown`}function x(e){let{limiter:t,logger:n}=e,r=e.keyGenerator??b;async function i(e,i,a){try{let i=e,o=r(e);i.clientIp=o;let s=e.path,c=`${o}:${s}`,l=await t.checkLimit(c);if(!l.allowed)throw n?.warn(`限流触发`,{clientIp:o,path:s}),new d;i.rateLimitRemaining=l.remaining,a()}catch(e){a(e)}}return i}function S(e){let{logger:t}=e;return(e,n,r)=>{let i=Date.now();t.info(`${e.method} ${e.originalUrl}`),n.on(`finish`,()=>{let r=Date.now()-i;t.info(`${e.method} ${e.originalUrl} ${n.statusCode} ${r}ms`)}),n.on(`error`,n=>{t.error(`${e.method} ${e.originalUrl} 请求错误`,{error:n instanceof Error?n.message:String(n)})}),r()}}function C(e={}){let{logger:n}=e;return(e,r,i,a)=>{if(e instanceof t){let t=h(e);i.status(t).json({code:e.code,message:e.message,...e.context&&Object.keys(e.context).length>0?{details:e.context}:{}});return}n?.error(`未预期的错误`,{error:e instanceof Error?e.message:String(e),stack:e instanceof Error?e.stack:void 0}),i.status(500).json({code:`INTERNAL_ERROR`,message:`服务器内部错误`})}}function w(e){return[g({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId}),C({logger:e.logger})]}function T(e){let t=v({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId});return[g({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId}),t(`*:*`),y({defaultTenantId:e.defaultTenantId,adapter:e.adapter}),x({limiter:e.rateLimiter,logger:e.logger}),C({logger:e.logger})]}function E(e){return e.headers[`x-forwarded-for`]?.split(`,`)[0]?.trim()??e.headers[`x-real-ip`]??e.ip??void 0}function D(e){return e.headers[`user-agent`]??void 0}export{w as createBasicPreset,C as createErrorHandlerMiddleware,g as createJwtVerifyMiddleware,S as createLoggerMiddleware,x as createRateLimitMiddleware,v as createRbacMiddleware,T as createStandardPreset,y as createTenantMiddleware,b as defaultKeyGenerator,E as extractClientIp,D as extractUserAgent,h as mapDomainErrorToStatus};
package/package.json CHANGED
@@ -1,22 +1,15 @@
1
1
  {
2
2
  "name": "@longzai-intelligence-auth/express",
3
- "version": "0.0.2",
3
+ "version": "0.0.6",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
- "main": "./dist/index.cjs",
8
- "module": "./dist/index.js",
7
+ "main": "./dist/index.js",
9
8
  "types": "./dist/index.d.ts",
10
9
  "exports": {
11
10
  ".": {
12
- "import": {
13
- "types": "./dist/index.d.ts",
14
- "default": "./dist/index.js"
15
- },
16
- "require": {
17
- "types": "./dist/index.d.cts",
18
- "default": "./dist/index.cjs"
19
- }
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
20
13
  }
21
14
  },
22
15
  "files": [
@@ -31,12 +24,7 @@
31
24
  "directory": "packages/express"
32
25
  },
33
26
  "dependencies": {
34
- "@longzai-intelligence-auth/core": "0.0.2",
35
- "@longzai-intelligence-auth/jwt": "0.0.2",
36
- "@longzai-intelligence-auth/rate-limit": "0.0.2",
37
- "@longzai-intelligence-auth/rbac": "0.0.2",
38
- "@longzai-intelligence-auth/session": "0.0.2",
39
- "@longzai-intelligence-auth/hashing": "0.0.2",
27
+ "@longzai-intelligence-auth/core": "0.0.6",
40
28
  "@longzai-intelligence/error": "^0.0.5"
41
29
  },
42
30
  "peerDependencies": {
@@ -47,8 +35,7 @@
47
35
  "@types/express": "^5"
48
36
  },
49
37
  "scripts": {
50
- "build": "bun build src/index.ts --outdir dist --target bun",
51
- "build:declaration": "tsgo --declaration --emitDeclarationOnly --outDir dist -p tsconfig/app.json",
38
+ "build": "tsgo --build tsconfig/build.json && resolve-aliases -p tsconfig/build.json",
52
39
  "build:prod": "NODE_ENV=production tsdown",
53
40
  "prepublishOnly": "bun run build:prod",
54
41
  "typecheck": "bun run typecheck:app && bun run typecheck:node && bun run typecheck:test",
@@ -60,6 +47,8 @@
60
47
  "test": "bun test",
61
48
  "test:watch": "bun test --watch",
62
49
  "test:coverage": "bun test --coverage",
63
- "clean": "rm -rf dist out .cache"
50
+ "test:unit": "bun test src/__tests__/unit/",
51
+ "test:integration": "bun test src/__tests__/integration/",
52
+ "clean": "rimraf dist out .cache"
64
53
  }
65
54
  }
@@ -1,2 +0,0 @@
1
- import type { DomainError } from "@longzai-intelligence/error";
2
- export declare function mapDomainErrorToStatus(error: DomainError): number;
@@ -1,27 +0,0 @@
1
- import { AuthenticationError, DuplicateEntityError, isValidationError, isEntityNotFoundError, isPermissionDeniedError, isBusinessRuleError, isConcurrencyError, } from "@longzai-intelligence/error";
2
- import { TokenExpiredError, TokenInvalidError, TokenMissingError, MfaRequiredError, InvalidCredentialsError, AccountDisabledError, RateLimitExceededError, } from "@longzai-intelligence-auth/core";
3
- export function mapDomainErrorToStatus(error) {
4
- if (isValidationError(error))
5
- return 400;
6
- if (error instanceof TokenExpiredError ||
7
- error instanceof TokenInvalidError ||
8
- error instanceof TokenMissingError ||
9
- error instanceof MfaRequiredError ||
10
- error instanceof InvalidCredentialsError ||
11
- error instanceof AccountDisabledError ||
12
- error instanceof AuthenticationError)
13
- return 401;
14
- if (isPermissionDeniedError(error))
15
- return 403;
16
- if (isEntityNotFoundError(error))
17
- return 404;
18
- if (error instanceof DuplicateEntityError)
19
- return 409;
20
- if (error instanceof RateLimitExceededError)
21
- return 429;
22
- if (isConcurrencyError(error))
23
- return 409;
24
- if (isBusinessRuleError(error))
25
- return 422;
26
- return 500;
27
- }
@@ -1,4 +0,0 @@
1
- import type { Request, Response, NextFunction } from "express";
2
- import type { AuditMiddlewareOptions } from "../types/express-auth.types";
3
- export type { AuditMiddlewareOptions };
4
- export declare function createAuditMiddleware(options: AuditMiddlewareOptions): (_req: Request, _res: Response, next: NextFunction) => void;
@@ -1,12 +0,0 @@
1
- export function createAuditMiddleware(options) {
2
- const { adapter } = options;
3
- return (_req, _res, next) => {
4
- const authReq = _req;
5
- authReq.recordAudit = (entry) => {
6
- adapter.audit.save(entry).catch((error) => {
7
- console.error("审计日志写入失败:", error);
8
- });
9
- };
10
- next();
11
- };
12
- }
@@ -1,4 +0,0 @@
1
- import type { Request, Response, NextFunction } from "express";
2
- import type { ErrorHandlerMiddlewareOptions } from "../types/express-auth.types";
3
- export type { ErrorHandlerMiddlewareOptions };
4
- export declare function createErrorHandlerMiddleware(options?: ErrorHandlerMiddlewareOptions): (error: Error, req: Request, res: Response, _next: NextFunction) => void;
@@ -1,23 +0,0 @@
1
- import { DomainError } from "@longzai-intelligence/error";
2
- import { mapDomainErrorToStatus } from "../core/error-mapper";
3
- export function createErrorHandlerMiddleware(options = {}) {
4
- const { logger } = options;
5
- return (error, req, res, _next) => {
6
- if (error instanceof DomainError) {
7
- const status = mapDomainErrorToStatus(error);
8
- res.status(status).json({
9
- code: error.code,
10
- message: error.message,
11
- ...(error.context && Object.keys(error.context).length > 0
12
- ? { details: error.context }
13
- : {}),
14
- });
15
- return;
16
- }
17
- logger?.error("未预期的错误", {
18
- error: error instanceof Error ? error.message : String(error),
19
- stack: error instanceof Error ? error.stack : undefined,
20
- });
21
- res.status(500).json({ code: "INTERNAL_ERROR", message: "服务器内部错误" });
22
- };
23
- }
@@ -1,4 +0,0 @@
1
- import type { Request, Response, NextFunction } from "express";
2
- import type { JwtVerifyMiddlewareOptions } from "../types/express-auth.types";
3
- export type { JwtVerifyMiddlewareOptions };
4
- export declare function createJwtVerifyMiddleware(options: JwtVerifyMiddlewareOptions): (req: Request, _res: Response, next: NextFunction) => Promise<void>;
@@ -1,36 +0,0 @@
1
- import { createJwtVerifier } from "@longzai-intelligence-auth/jwt";
2
- import { TokenMissingError, TokenInvalidError } from "@longzai-intelligence-auth/core";
3
- export function createJwtVerifyMiddleware(options) {
4
- const { jwt: jwtConfig, defaultTenantId = "default" } = options;
5
- let verifierPromise = null;
6
- const getVerifier = () => {
7
- if (!verifierPromise) {
8
- verifierPromise = createJwtVerifier(jwtConfig);
9
- }
10
- return verifierPromise;
11
- };
12
- return async (req, _res, next) => {
13
- try {
14
- const authReq = req;
15
- const authHeader = req.headers["authorization"];
16
- const bearer = typeof authHeader === "string" && authHeader.startsWith("Bearer ")
17
- ? authHeader.slice(7)
18
- : null;
19
- if (!bearer) {
20
- throw new TokenMissingError();
21
- }
22
- const verifier = await getVerifier();
23
- const result = await verifier.verifyAccessToken(bearer);
24
- if (!result.success || !result.payload) {
25
- throw new TokenInvalidError(result.error);
26
- }
27
- const payload = result.payload;
28
- authReq.auth = payload;
29
- authReq.tenantId = payload.tenantId ?? defaultTenantId;
30
- next();
31
- }
32
- catch (error) {
33
- next(error);
34
- }
35
- };
36
- }
@@ -1,4 +0,0 @@
1
- import type { Request, Response, NextFunction } from "express";
2
- import type { LoggerMiddlewareOptions } from "../types/express-auth.types";
3
- export type { LoggerMiddlewareOptions };
4
- export declare function createLoggerMiddleware(options: LoggerMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => void;
@@ -1,17 +0,0 @@
1
- export function createLoggerMiddleware(options) {
2
- const { logger } = options;
3
- return (req, res, next) => {
4
- const startTime = Date.now();
5
- logger.info(`${req.method} ${req.originalUrl}`);
6
- res.on("finish", () => {
7
- const duration = Date.now() - startTime;
8
- logger.info(`${req.method} ${req.originalUrl} ${res.statusCode} ${duration}ms`);
9
- });
10
- res.on("error", (error) => {
11
- logger.error(`${req.method} ${req.originalUrl} 请求错误`, {
12
- error: error instanceof Error ? error.message : String(error),
13
- });
14
- });
15
- next();
16
- };
17
- }
@@ -1,4 +0,0 @@
1
- import type { Request, Response, NextFunction } from "express";
2
- import type { RateLimitMiddlewareOptions } from "../types/express-auth.types";
3
- export type { RateLimitMiddlewareOptions };
4
- export declare function createRateLimitMiddleware(options?: RateLimitMiddlewareOptions): (req: Request, _res: Response, next: NextFunction) => Promise<void>;
@@ -1,42 +0,0 @@
1
- import { createMemoryRateLimiter } from "@longzai-intelligence-auth/rate-limit";
2
- import { RateLimitExceededError } from "@longzai-intelligence-auth/core";
3
- function defaultKeyGenerator(req) {
4
- return req.headers["x-forwarded-for"]?.split(",")[0]?.trim()
5
- ?? req.headers["x-real-ip"]
6
- ?? req.ip
7
- ?? "unknown";
8
- }
9
- export function createRateLimitMiddleware(options = { windowSeconds: 60, maxRequests: 100 }) {
10
- const { logger } = options;
11
- const keyGen = options.keyGenerator ?? defaultKeyGenerator;
12
- const limiter = createMemoryRateLimiter({
13
- windowSeconds: options.windowSeconds,
14
- maxRequests: options.maxRequests,
15
- });
16
- const timer = setInterval(() => {
17
- limiter.cleanup();
18
- }, 60_000);
19
- if (typeof process !== "undefined" && typeof process.on === "function") {
20
- process.on("exit", () => clearInterval(timer));
21
- }
22
- return async (req, _res, next) => {
23
- try {
24
- const authReq = req;
25
- const clientIp = keyGen(req);
26
- authReq.clientIp = clientIp;
27
- const path = req.path;
28
- const key = `${clientIp}:${path}`;
29
- const allowed = await limiter.check(key);
30
- if (!allowed) {
31
- logger?.warn("限流触发", { clientIp, path });
32
- throw new RateLimitExceededError();
33
- }
34
- const remaining = options.maxRequests - limiter.getCount(key);
35
- authReq.rateLimitRemaining = remaining;
36
- next();
37
- }
38
- catch (error) {
39
- next(error);
40
- }
41
- };
42
- }
@@ -1,4 +0,0 @@
1
- import type { Request, Response, NextFunction } from "express";
2
- import type { RbacMiddlewareOptions } from "../types/express-auth.types";
3
- export type { RbacMiddlewareOptions };
4
- export declare function createRbacMiddleware(options: RbacMiddlewareOptions): (permission: string) => (req: Request, _res: Response, next: NextFunction) => Promise<void>;
@@ -1,49 +0,0 @@
1
- import { createRoleChecker } from "@longzai-intelligence-auth/rbac";
2
- import { createJwtVerifier } from "@longzai-intelligence-auth/jwt";
3
- import { TokenMissingError, TokenInvalidError } from "@longzai-intelligence-auth/core";
4
- export function createRbacMiddleware(options) {
5
- const { jwt: jwtConfig, defaultTenantId = "default" } = options;
6
- const roleChecker = createRoleChecker();
7
- let verifierPromise = null;
8
- const getVerifier = () => {
9
- if (!verifierPromise) {
10
- verifierPromise = createJwtVerifier(jwtConfig);
11
- }
12
- return verifierPromise;
13
- };
14
- return (permission) => {
15
- return async (req, _res, next) => {
16
- try {
17
- const authReq = req;
18
- const authHeader = req.headers["authorization"];
19
- const bearer = typeof authHeader === "string" && authHeader.startsWith("Bearer ")
20
- ? authHeader.slice(7)
21
- : null;
22
- if (!bearer) {
23
- throw new TokenMissingError();
24
- }
25
- const verifier = await getVerifier();
26
- const result = await verifier.verifyAccessToken(bearer);
27
- if (!result.success || !result.payload) {
28
- throw new TokenInvalidError(result.error);
29
- }
30
- const payload = result.payload;
31
- authReq.auth = payload;
32
- authReq.tenantId = payload.tenantId ?? defaultTenantId;
33
- const [resource, action] = permission.split(":");
34
- if (!resource || !action) {
35
- throw new Error(`无效的权限格式: ${permission},应为 resource:action`);
36
- }
37
- const hasPermission = roleChecker.hasPermission(payload, resource, action);
38
- if (!hasPermission) {
39
- const { PermissionDeniedError } = await import("@longzai-intelligence/error");
40
- throw new PermissionDeniedError(resource, action);
41
- }
42
- next();
43
- }
44
- catch (error) {
45
- next(error);
46
- }
47
- };
48
- };
49
- }
@@ -1,4 +0,0 @@
1
- import type { Request, Response, NextFunction } from "express";
2
- import type { TenantMiddlewareOptions } from "../types/express-auth.types";
3
- export type { TenantMiddlewareOptions };
4
- export declare function createTenantMiddleware(options?: TenantMiddlewareOptions): (req: Request, _res: Response, next: NextFunction) => Promise<void>;
@@ -1,22 +0,0 @@
1
- export function createTenantMiddleware(options = {}) {
2
- const { defaultTenantId = "default", adapter } = options;
3
- return async (req, _res, next) => {
4
- try {
5
- const authReq = req;
6
- const headerTenantId = req.headers["x-tenant-id"];
7
- const tenantId = headerTenantId ?? defaultTenantId;
8
- authReq.tenantId = tenantId;
9
- if (adapter && tenantId !== defaultTenantId) {
10
- const result = await adapter.tenant.validateStatus(tenantId);
11
- if (!result.valid) {
12
- const { PermissionDeniedError } = await import("@longzai-intelligence/error");
13
- throw new PermissionDeniedError("tenant", "access");
14
- }
15
- }
16
- next();
17
- }
18
- catch (error) {
19
- next(error);
20
- }
21
- };
22
- }
@@ -1,4 +0,0 @@
1
- import type { RequestHandler } from "express";
2
- import type { BasicPresetOptions } from "../types/express-auth.types";
3
- export type { BasicPresetOptions };
4
- export declare function createBasicPreset(options: BasicPresetOptions): RequestHandler[];
@@ -1,11 +0,0 @@
1
- import { createJwtVerifyMiddleware } from "../middlewares/jwt-verify.middleware";
2
- import { createErrorHandlerMiddleware } from "../middlewares/error-handler.middleware";
3
- export function createBasicPreset(options) {
4
- return [
5
- createJwtVerifyMiddleware({
6
- jwt: options.jwt,
7
- defaultTenantId: options.defaultTenantId,
8
- }),
9
- createErrorHandlerMiddleware({ logger: options.logger }),
10
- ];
11
- }
@@ -1,4 +0,0 @@
1
- import type { RequestHandler } from "express";
2
- import type { StandardPresetOptions } from "../types/express-auth.types";
3
- export type { StandardPresetOptions };
4
- export declare function createStandardPreset(options: StandardPresetOptions): RequestHandler[];
@@ -1,27 +0,0 @@
1
- import { createJwtVerifyMiddleware } from "../middlewares/jwt-verify.middleware";
2
- import { createRbacMiddleware } from "../middlewares/rbac.middleware";
3
- import { createTenantMiddleware } from "../middlewares/tenant.middleware";
4
- import { createRateLimitMiddleware } from "../middlewares/rate-limit.middleware";
5
- import { createErrorHandlerMiddleware } from "../middlewares/error-handler.middleware";
6
- export function createStandardPreset(options) {
7
- const rbacMiddleware = createRbacMiddleware({
8
- jwt: options.jwt,
9
- defaultTenantId: options.defaultTenantId,
10
- });
11
- return [
12
- createJwtVerifyMiddleware({
13
- jwt: options.jwt,
14
- defaultTenantId: options.defaultTenantId,
15
- }),
16
- rbacMiddleware("*:*"),
17
- createTenantMiddleware({
18
- defaultTenantId: options.defaultTenantId,
19
- adapter: options.adapter,
20
- }),
21
- createRateLimitMiddleware({
22
- windowSeconds: 60,
23
- maxRequests: 100,
24
- }),
25
- createErrorHandlerMiddleware({ logger: options.logger }),
26
- ];
27
- }
@@ -1,47 +0,0 @@
1
- import type { Request } from "express";
2
- import type { JwtSignerConfig } from "@longzai-intelligence-auth/jwt";
3
- import type { IdentityAuthBackend, RateLimitConfig, LoggerService, AuditLogEntry } from "@longzai-intelligence-auth/core";
4
- import type { AccessTokenPayload } from "@longzai-intelligence-auth/core";
5
- export interface AuthRequest extends Request {
6
- auth: AccessTokenPayload;
7
- tenantId: string;
8
- clientIp?: string;
9
- rateLimitRemaining?: number;
10
- recordAudit?: (entry: Omit<AuditLogEntry, never>) => void;
11
- }
12
- export type JwtVerifyMiddlewareOptions = {
13
- jwt: JwtSignerConfig;
14
- defaultTenantId?: string;
15
- };
16
- export type RbacMiddlewareOptions = {
17
- jwt: JwtSignerConfig;
18
- defaultTenantId?: string;
19
- };
20
- export type TenantMiddlewareOptions = {
21
- defaultTenantId?: string;
22
- adapter?: IdentityAuthBackend;
23
- };
24
- export type RateLimitMiddlewareOptions = RateLimitConfig & {
25
- logger?: LoggerService;
26
- keyGenerator?: (req: Request) => string;
27
- };
28
- export type AuditMiddlewareOptions = {
29
- adapter: IdentityAuthBackend;
30
- };
31
- export type LoggerMiddlewareOptions = {
32
- logger: LoggerService;
33
- };
34
- export type ErrorHandlerMiddlewareOptions = {
35
- logger?: LoggerService;
36
- };
37
- export type BasicPresetOptions = {
38
- jwt: JwtSignerConfig;
39
- defaultTenantId?: string;
40
- logger?: LoggerService;
41
- };
42
- export type StandardPresetOptions = {
43
- jwt: JwtSignerConfig;
44
- defaultTenantId?: string;
45
- adapter: IdentityAuthBackend;
46
- logger?: LoggerService;
47
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,2 +0,0 @@
1
- import type { Request } from "express";
2
- export declare function extractClientIp(req: Request): string | undefined;
@@ -1,6 +0,0 @@
1
- export function extractClientIp(req) {
2
- return req.headers["x-forwarded-for"]?.split(",")[0]?.trim()
3
- ?? req.headers["x-real-ip"]
4
- ?? req.ip
5
- ?? undefined;
6
- }
@@ -1,2 +0,0 @@
1
- import type { Request } from "express";
2
- export declare function extractUserAgent(req: Request): string | undefined;
@@ -1,3 +0,0 @@
1
- export function extractUserAgent(req) {
2
- return req.headers["user-agent"] ?? undefined;
3
- }