@longzai-intelligence-auth/elysia 0.0.7 → 0.0.8
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 +55 -1
- package/dist/index.js +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -129,6 +129,27 @@ type BearerExtractorOptions = {
|
|
|
129
129
|
*/
|
|
130
130
|
declare function createBearerExtractor(options?: BearerExtractorOptions): CredentialExtractor;
|
|
131
131
|
//#endregion
|
|
132
|
+
//#region src/extractors/api-key-extractor.d.ts
|
|
133
|
+
/**
|
|
134
|
+
* API Key 提取器配置
|
|
135
|
+
*/
|
|
136
|
+
type ApiKeyExtractorOptions = {
|
|
137
|
+
/**
|
|
138
|
+
* 头字段名(默认 "x-api-key")
|
|
139
|
+
* 大小写不敏感:先精确匹配,再尝试小写形式(HTTP header 字段名本身大小写不敏感)
|
|
140
|
+
*/
|
|
141
|
+
headerName?: string;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* 创建 API Key 凭证提取器
|
|
145
|
+
*
|
|
146
|
+
* 不做任何令牌格式校验(由 verifier 负责)。
|
|
147
|
+
*
|
|
148
|
+
* @param options - API Key 提取器配置
|
|
149
|
+
* @returns 实现 CredentialExtractor 的 api-key 提取器
|
|
150
|
+
*/
|
|
151
|
+
declare function createApiKeyExtractor(options?: ApiKeyExtractorOptions): CredentialExtractor;
|
|
152
|
+
//#endregion
|
|
132
153
|
//#region src/verifiers/cookie-jwt-verifier.d.ts
|
|
133
154
|
/**
|
|
134
155
|
* Cookie JWT 验证器配置
|
|
@@ -159,9 +180,42 @@ type CookieJwtVerifierOptions = {
|
|
|
159
180
|
*
|
|
160
181
|
* @param options - Cookie JWT 验证器配置
|
|
161
182
|
* @returns 实现 RequestTokenVerifier 的组合验证器
|
|
183
|
+
*
|
|
184
|
+
* @throws {@link Error} 当 verifier 和 jwt 都未提供时
|
|
162
185
|
*/
|
|
163
186
|
declare function createCookieJwtVerifier(options: CookieJwtVerifierOptions): RequestTokenVerifier;
|
|
164
187
|
//#endregion
|
|
188
|
+
//#region src/verifiers/bearer-jwt-verifier.d.ts
|
|
189
|
+
/**
|
|
190
|
+
* Bearer JWT 验证器配置
|
|
191
|
+
*/
|
|
192
|
+
type BearerJwtVerifierOptions = {
|
|
193
|
+
/**
|
|
194
|
+
* JWT 配置(与 verifier 二选一)
|
|
195
|
+
* 提供时内部创建 JwtTokenVerifier 实例
|
|
196
|
+
*/
|
|
197
|
+
jwt?: JwtConfig;
|
|
198
|
+
/**
|
|
199
|
+
* 已构造的 TokenVerifierPort(与 jwt 二选一)
|
|
200
|
+
* 用于注入自定义 verifier(如多策略、远程校验等)
|
|
201
|
+
*/
|
|
202
|
+
verifier?: TokenVerifierPort;
|
|
203
|
+
/**
|
|
204
|
+
* 自定义凭证提取器(高级用法)
|
|
205
|
+
* 默认使用 createBearerExtractor()(标准 Authorization: Bearer 头)
|
|
206
|
+
*/
|
|
207
|
+
extractor?: CredentialExtractor;
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* 创建 Bearer JWT 验证器
|
|
211
|
+
*
|
|
212
|
+
* @param options - Bearer JWT 验证器配置
|
|
213
|
+
* @returns 实现 RequestTokenVerifier 的组合验证器
|
|
214
|
+
*
|
|
215
|
+
* @throws {@link Error} 当 verifier 和 jwt 都未提供时
|
|
216
|
+
*/
|
|
217
|
+
declare function createBearerJwtVerifier(options: BearerJwtVerifierOptions): RequestTokenVerifier;
|
|
218
|
+
//#endregion
|
|
165
219
|
//#region src/plugins/jwt-verify.plugin.d.ts
|
|
166
220
|
/** JWT 验证插件解析后的认证上下文 */
|
|
167
221
|
type VerifiedAuthContext = {
|
|
@@ -1022,4 +1076,4 @@ declare function extractClientIp(request: Request): string | undefined;
|
|
|
1022
1076
|
*/
|
|
1023
1077
|
declare function extractUserAgent(request: Request): string | undefined;
|
|
1024
1078
|
//#endregion
|
|
1025
|
-
export { type ApiKeyPluginOptions, type ApiKeyPrincipal, type AuthContextWithExtra, type BasicPresetOptions, type BearerExtractorOptions, type CompositeAuthContext, type CompositeAuthPluginOptions, type CookieExtractorOptions, type CookieJwtVerifierOptions, type CredentialExtractor, type ErrorHandlerPluginOptions, type ExtractExtra, type InMemoryApiKeyEntry, type InMemoryApiKeyMap, type JwtVerifyPluginOptions, type LoggerPluginOptions, type OptionalAuthContext, type OptionalJwtPluginOptions, type RateLimitPluginOptions, type RbacPluginOptions, type RequestTokenVerifier, type StandardPresetOptions, type StaticTokenVerifierOptions, type UnifiedAuthContext, type UserRoleStrategy, type VerifiedAuthContext, createApiKeyPlugin, createBasicPreset, createBearerExtractor, createCompositeAuthPlugin, createCookieExtractor, createCookieJwtVerifier, createErrorHandlerPlugin, createInMemoryApiKeyValidator, createJwtVerifyPlugin, createLoggerPlugin, createOptionalJwtPlugin, createRateLimitPlugin, createRbacPlugin, createRequiredCompositeAuthPlugin, createStandardPreset, createStaticTokenVerifier, extractClientIp, extractUserAgent, mapDomainErrorToStatus };
|
|
1079
|
+
export { type ApiKeyExtractorOptions, type ApiKeyPluginOptions, type ApiKeyPrincipal, type AuthContextWithExtra, type BasicPresetOptions, type BearerExtractorOptions, type BearerJwtVerifierOptions, type CompositeAuthContext, type CompositeAuthPluginOptions, type CookieExtractorOptions, type CookieJwtVerifierOptions, type CredentialExtractor, type ErrorHandlerPluginOptions, type ExtractExtra, type InMemoryApiKeyEntry, type InMemoryApiKeyMap, type JwtVerifyPluginOptions, type LoggerPluginOptions, type OptionalAuthContext, type OptionalJwtPluginOptions, type RateLimitPluginOptions, type RbacPluginOptions, type RequestTokenVerifier, type StandardPresetOptions, type StaticTokenVerifierOptions, type UnifiedAuthContext, type UserRoleStrategy, type VerifiedAuthContext, createApiKeyExtractor, createApiKeyPlugin, createBasicPreset, createBearerExtractor, createBearerJwtVerifier, createCompositeAuthPlugin, createCookieExtractor, createCookieJwtVerifier, createErrorHandlerPlugin, createInMemoryApiKeyValidator, createJwtVerifyPlugin, createLoggerPlugin, createOptionalJwtPlugin, createRateLimitPlugin, createRbacPlugin, createRequiredCompositeAuthPlugin, createStandardPreset, createStaticTokenVerifier, extractClientIp, extractUserAgent, mapDomainErrorToStatus };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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,UserAlreadyExistsError as h,accessTokenPayloadSchema as g,createDefaultJwtConfig as _}from"@longzai-intelligence-auth/core";import v from"node:crypto";import{JwtTokenVerifier as y}from"@longzai-intelligence-auth/jwt";import{Elysia as b}from"elysia";function x(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||t instanceof h?409:t instanceof d?429:i(t)?409:r(t)||t.code===`PASSWORD_POLICY_VIOLATION`?422:500}function S(e,t){let n=Buffer.from(e,`utf-8`),r=Buffer.from(t,`utf-8`);if(n.length!==r.length){let e=Buffer.alloc(n.length);return v.timingSafeEqual(n,e),!1}return v.timingSafeEqual(n,r)}function C(e){let{token:t,getToken:n,subject:r=`static`,tenantId:i}=e;if(!t&&!n)throw Error(`createStaticTokenVerifier 需要至少提供 token 或 getToken 之一`);let a=()=>{if(n){let e=n();if(e)return e}return t??null};return{async verifyAccessToken(e){let t=a();return t?S(e,t)?{success:!0,payload:{sub:r,type:`access`,...i!==void 0&&{tenantId:i}}}:{success:!1,error:`静态令牌不匹配`}:{success:!1,error:`静态令牌未配置`}},async verifyRefreshToken(){return{success:!1,error:`静态令牌模式不支持 refresh token`}}}}function w(e){let{cookieName:t}=e;return{extract(e){let n=e.headers.get(`cookie`);if(!n)return null;let r=n.split(`;`);for(let e of r){let n=e.indexOf(`=`);if(n!==-1&&e.slice(0,n).trim()===t)return e.slice(n+1).trim()||null}return null}}}function T(e={}){let{headerName:t=`authorization`}=e;return{extract(e){let n=e.headers.get(t);if(!n)return null;let r=n.split(` `);return r.length!==2||r[0]!==`Bearer`||!r[1]?null:r[1]}}}function E(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function D(e,t){if(e)return e;if(!t)throw Error(`createCookieJwtVerifier 需要至少提供 jwt 或 verifier 之一`);return new y(E(t))}function O(e){let{cookieName:t,jwt:n,verifier:r,extractor:i}=e,a=D(r,n),o=i??w({cookieName:t});return{async verify(e){let t=o.extract(e);return t?a.verifyAccessToken(t):{success:!1,error:`请求未携带 cookie 凭证`}}}}function k(e,t){return{userId:e.sub,tenantId:e.tenantId??t,roles:e.roles??[],permissions:e.permissions??[],authMethod:`jwt`}}function A(e){return{userId:``,tenantId:e,roles:[],permissions:[],authMethod:`jwt`}}function j(e,t){return t.some(t=>t.endsWith(`/*`)?e.startsWith(t.slice(0,-2)):e===t)}function M(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function N(e,t){return e||new y(M(t??_()))}function P(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,publicPaths:i=[],extendSchema:a}=e,o=N(t,n);return new b({name:`@longzai-intelligence-auth/jwt-verify`}).derive(async({request:e})=>{if(j(new URL(e.url).pathname,i)){let e=a?a.parse({}):{};return{auth:{...A(r),...e}}}let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(!n)throw new m;let s=await o.verifyAccessToken(n);if(!s.success||!s.payload)throw new p(s.error);g.parse(s.payload);let c=k(s.payload,r),l=a?a.parse(s.payload):{};return{auth:{...c,...l}}}).as(`scoped`)}function F(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function I(e,t){return e||new y(F(t??_()))}function L(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,extendSchema:i}=e,a=I(t,n);return new b({name:`@longzai-intelligence-auth/optional-jwt`}).derive(async({request:e})=>{let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(!n)return{auth:null};try{let e=await a.verifyAccessToken(n);if(!e.success||!e.payload)return{auth:null};g.parse(e.payload);let t=e.payload,o={userId:t.sub,tenantId:t.tenantId??r,roles:t.roles??[],permissions:t.permissions??[],authMethod:`jwt`},s=i?i.parse(t):{};return{auth:{...o,...s}}}catch{return{auth:null}}}).as(`scoped`)}function R(e,t,n){return e.some(e=>e.resource===`*`&&e.action===`*`||e.resource===t&&e.action===`*`||e.resource===`*`&&e.action===n||e.resource===t&&e.action===n)}function z(e,t,n){let r=`${t}:${n}`;return e.includes(r)||e.includes(`${t}:*`)||e.includes(`*:${n}`)||e.includes(`*:*`)}function B(e={}){let{userRole:t}=e;return new b({name:`@longzai-intelligence-auth/rbac`}).derive({as:`scoped`},async e=>{let n=e.auth;if(!n)throw new m;let r=n.userId,i=n.tenantId;return{requirePermission:async(e,a)=>{if(t){if(R(await t.findPermissionsByUserId(r,i),e,a))return;let{PermissionDeniedError:n}=await import(`@longzai-intelligence/error`);throw new n(e,a)}if(z(n.permissions??[],e,a))return;let{PermissionDeniedError:o}=await import(`@longzai-intelligence/error`);throw new o(e,a)}}}).as(`global`)}function V(e){let{header:t=`x-api-key`,validator:n}=e;return new b({name:`@longzai-intelligence-auth/api-key`}).derive(async({request:e})=>{let r=e.headers.get(t)??e.headers.get(t.toLowerCase());if(!r)throw new m(`缺少 API Key`);let i=await n(r);if(!i)throw new p(`无效的 API Key`);return{auth:{userId:i.principalId,tenantId:i.tenantId??`default`,roles:i.roles,permissions:i.permissions,authMethod:`api-key`}}}).as(`scoped`)}function H(e){return async t=>{let n=e[t];return n?{principalId:n.principalId,tenantId:n.tenantId,roles:n.roles,permissions:n.permissions}:null}}function U(e){return{authMethod:`jwt`,userId:e.userId,tenantId:e.tenantId,roles:e.roles,permissions:e.permissions}}function W(e,t){return{authMethod:`api-key`,userId:e.principalId,tenantId:e.tenantId??t,roles:e.roles,permissions:e.permissions}}function G(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function K(e,t,n){let r=[];return e&&r.push(e),t&&t.length>0&&r.push(...t),r.length>0?r:[new y(G(n??_()))]}function q(e,t){return t.some(t=>t.endsWith(`/*`)?e.startsWith(t.slice(0,-2)):e===t)}async function J(e,t){for(let n of e)try{let e=await n.verifyAccessToken(t);if(e.success&&e.payload)return{success:!0,payload:e.payload}}catch{}return null}function Y(e){let{verifier:t,verifiers:n,jwt:r,defaultTenantId:i=`default`,apiKeyValidator:a,apiKeyHeader:o=`x-api-key`,publicPaths:s=[]}=e,c=K(t,n,r);return new b({name:`@longzai-intelligence-auth/composite-auth`}).derive(async({request:e})=>{if(q(new URL(e.url).pathname,s))return{auth:null};let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(n){let e=await J(c,n);if(e)return g.parse(e.payload),{auth:U({userId:e.payload.sub,tenantId:e.payload.tenantId??i,roles:e.payload.roles??[],permissions:e.payload.permissions??[]})}}if(a){let t=e.headers.get(o)??e.headers.get(o.toLowerCase());if(t){let e=await a(t);if(e)return{auth:W(e,i)}}}return{auth:null}}).as(`scoped`)}function X(e){let{verifier:t,verifiers:n,jwt:r,defaultTenantId:i=`default`,apiKeyValidator:a,apiKeyHeader:o=`x-api-key`,publicPaths:s=[]}=e,c=K(t,n,r);return new b({name:`@longzai-intelligence-auth/required-composite-auth`}).derive(async({request:e})=>{if(q(new URL(e.url).pathname,s))return{auth:{authMethod:`jwt`,userId:``,tenantId:i,roles:[],permissions:[]}};let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(n){let e=await J(c,n);if(e)return g.parse(e.payload),{auth:U({userId:e.payload.sub,tenantId:e.payload.tenantId??i,roles:e.payload.roles??[],permissions:e.payload.permissions??[]})}}if(a){let t=e.headers.get(o)??e.headers.get(o.toLowerCase());if(t){let e=await a(t);if(e)return{auth:W(e,i)}}}throw Error(`认证失败:需要提供有效的 JWT Token 或 API Key`)}).as(`scoped`)}function Z(e){return e.headers.get(`x-forwarded-for`)?.split(`,`)[0]?.trim()??e.headers.get(`x-real-ip`)??`unknown`}function Q(e){let{limiter:t,logger:n}=e,r=e.keyGenerator??Z;return new b({name:`@longzai-intelligence-auth/rate-limit`}).derive(({request:e})=>({clientIp:r(e)})).derive(async({clientIp:e,request:r})=>{let i=new URL(r.url).pathname,a=`${e}:${i}`,o=await t.checkLimit(a);if(!o.allowed)throw n?.warn(`限流触发`,{clientIp:e,path:i}),new d;return{rateLimitRemaining:o.remaining}}).as(`global`)}function $(e={}){let{logger:n}=e;return new b({name:`@longzai-intelligence-auth/error-handler`}).onError(({code:e,error:r,set:i})=>{if(r instanceof t)return i.status=x(r),{code:r.code,message:r.message,...r.context&&Object.keys(r.context).length>0?{details:r.context}:{}};switch(e){case`VALIDATION`:return i.status=400,{code:`VALIDATION_ERROR`,message:`请求参数验证失败`,details:r.all.map(e=>({path:e.path,message:e.summary}))};case`NOT_FOUND`:return i.status=404,{code:`NOT_FOUND`,message:`未找到请求的资源`};case`PARSE`:return i.status=400,{code:`PARSE_ERROR`,message:`请求数据解析失败`};default:return n?.error(`未预期的错误`,{error:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}),i.status=500,{code:`INTERNAL_ERROR`,message:`服务器内部错误`}}}).as(`global`)}function ee(e){let{logger:t}=e;return new b({name:`@longzai-intelligence-auth/logger`}).onRequest(({request:e})=>{t.info(`${e.method} ${e.url}`)}).onAfterResponse(({request:e,set:n})=>{t.info(`${e.method} ${e.url} ${n.status}`)}).onError(({request:e,error:n})=>{t.error(`${e.method} ${e.url} 请求错误`,{error:n instanceof Error?n.message:String(n)})}).as(`global`)}function te(e){return new b({name:`@longzai-intelligence-auth/basic-preset`}).use(P({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,extendSchema:e.extendSchema})).use($({logger:e.logger}))}function ne(e){let t=e.apiKeyValidator?X({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,apiKeyValidator:e.apiKeyValidator}):P({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,extendSchema:e.extendSchema}),n=new b({name:`@longzai-intelligence-auth/standard-preset`}).use(t).use(B({userRole:e.userRole}));return e.rateLimiter&&n.use(Q({limiter:e.rateLimiter,logger:e.logger})),n.use($({logger:e.logger}))}function re(e){return e.headers.get(`x-forwarded-for`)?.split(`,`)[0]?.trim()??e.headers.get(`x-real-ip`)??void 0}function ie(e){return e.headers.get(`user-agent`)??void 0}export{V as createApiKeyPlugin,te as createBasicPreset,T as createBearerExtractor,Y as createCompositeAuthPlugin,w as createCookieExtractor,O as createCookieJwtVerifier,$ as createErrorHandlerPlugin,H as createInMemoryApiKeyValidator,P as createJwtVerifyPlugin,ee as createLoggerPlugin,L as createOptionalJwtPlugin,Q as createRateLimitPlugin,B as createRbacPlugin,X as createRequiredCompositeAuthPlugin,ne as createStandardPreset,C as createStaticTokenVerifier,re as extractClientIp,ie as extractUserAgent,x as mapDomainErrorToStatus};
|
|
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 ee,TokenInvalidError as f,TokenMissingError as p,UserAlreadyExistsError as m,accessTokenPayloadSchema as h,createDefaultJwtConfig as g}from"@longzai-intelligence-auth/core";import _ from"node:crypto";import{JwtTokenVerifier as v}from"@longzai-intelligence-auth/jwt";import{Elysia as y}from"elysia";function b(t){return s(t)?400:t instanceof ee||t instanceof f||t instanceof p||t instanceof u||t instanceof l||t instanceof c||t instanceof e?401:o(t)?403:a(t)?404:t instanceof n||t instanceof m?409:t instanceof d?429:i(t)?409:r(t)||t.code===`PASSWORD_POLICY_VIOLATION`?422:500}function x(e,t){let n=Buffer.from(e,`utf-8`),r=Buffer.from(t,`utf-8`);if(n.length!==r.length){let e=Buffer.alloc(n.length);return _.timingSafeEqual(n,e),!1}return _.timingSafeEqual(n,r)}function S(e){let{token:t,getToken:n,subject:r=`static`,tenantId:i}=e;if(!t&&!n)throw Error(`createStaticTokenVerifier 需要至少提供 token 或 getToken 之一`);let a=()=>{if(n){let e=n();if(e)return e}return t??null};return{async verifyAccessToken(e){let t=a();return t?x(e,t)?{success:!0,payload:{sub:r,type:`access`,...i!==void 0&&{tenantId:i}}}:{success:!1,error:`静态令牌不匹配`}:{success:!1,error:`静态令牌未配置`}},async verifyRefreshToken(){return{success:!1,error:`静态令牌模式不支持 refresh token`}}}}function C(e){let{cookieName:t}=e;return{extract(e){let n=e.headers.get(`cookie`);if(!n)return null;let r=n.split(`;`);for(let e of r){let n=e.indexOf(`=`);if(n!==-1&&e.slice(0,n).trim()===t)return e.slice(n+1).trim()||null}return null}}}function w(e={}){let{headerName:t=`authorization`}=e;return{extract(e){let n=e.headers.get(t);if(!n)return null;let r=n.split(` `);return r.length!==2||r[0]!==`Bearer`||!r[1]?null:r[1]}}}function T(e={}){let{headerName:t=`x-api-key`}=e;return{extract(e){return e.headers.get(t)??e.headers.get(t.toLowerCase())??null}}}function E(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function D(e,t,n){if(e)return e;if(!t)throw Error(`${n} 需要至少提供 jwt 或 verifier 之一`);return new v(E(t))}async function O(e,t,n,r){let i=t.extract(e);return i?n.verifyAccessToken(i):{success:!1,error:r}}function k(e){let{cookieName:t,jwt:n,verifier:r,extractor:i}=e,a=D(r,n,`createCookieJwtVerifier`),o=i??C({cookieName:t});return{async verify(e){return O(e,o,a,`请求未携带 cookie 凭证`)}}}function A(e){let{jwt:t,verifier:n,extractor:r}=e,i=D(n,t,`createBearerJwtVerifier`),a=r??w();return{async verify(e){return O(e,a,i,`请求未携带 Bearer 凭证`)}}}function te(e,t){return{userId:e.sub,tenantId:e.tenantId??t,roles:e.roles??[],permissions:e.permissions??[],authMethod:`jwt`}}function j(e){return{userId:``,tenantId:e,roles:[],permissions:[],authMethod:`jwt`}}function M(e,t){return t.some(t=>t.endsWith(`/*`)?e.startsWith(t.slice(0,-2)):e===t)}function N(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function P(e,t){return e||new v(N(t??g()))}function F(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,publicPaths:i=[],extendSchema:a}=e,o=P(t,n);return new y({name:`@longzai-intelligence-auth/jwt-verify`}).derive(async({request:e})=>{if(M(new URL(e.url).pathname,i)){let e=a?a.parse({}):{};return{auth:{...j(r),...e}}}let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(!n)throw new p;let s=await o.verifyAccessToken(n);if(!s.success||!s.payload)throw new f(s.error);h.parse(s.payload);let c=te(s.payload,r),l=a?a.parse(s.payload):{};return{auth:{...c,...l}}}).as(`scoped`)}function I(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function L(e,t){return e||new v(I(t??g()))}function R(e){let{verifier:t,jwt:n,defaultTenantId:r=`default`,extendSchema:i}=e,a=L(t,n);return new y({name:`@longzai-intelligence-auth/optional-jwt`}).derive(async({request:e})=>{let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(!n)return{auth:null};try{let e=await a.verifyAccessToken(n);if(!e.success||!e.payload)return{auth:null};h.parse(e.payload);let t=e.payload,o={userId:t.sub,tenantId:t.tenantId??r,roles:t.roles??[],permissions:t.permissions??[],authMethod:`jwt`},s=i?i.parse(t):{};return{auth:{...o,...s}}}catch{return{auth:null}}}).as(`scoped`)}function z(e,t,n){return e.some(e=>e.resource===`*`&&e.action===`*`||e.resource===t&&e.action===`*`||e.resource===`*`&&e.action===n||e.resource===t&&e.action===n)}function B(e,t,n){let r=`${t}:${n}`;return e.includes(r)||e.includes(`${t}:*`)||e.includes(`*:${n}`)||e.includes(`*:*`)}function V(e={}){let{userRole:t}=e;return new y({name:`@longzai-intelligence-auth/rbac`}).derive({as:`scoped`},async e=>{let n=e.auth;if(!n)throw new p;let r=n.userId,i=n.tenantId;return{requirePermission:async(e,a)=>{if(t){if(z(await t.findPermissionsByUserId(r,i),e,a))return;let{PermissionDeniedError:n}=await import(`@longzai-intelligence/error`);throw new n(e,a)}if(B(n.permissions??[],e,a))return;let{PermissionDeniedError:o}=await import(`@longzai-intelligence/error`);throw new o(e,a)}}}).as(`global`)}function H(e){let{header:t=`x-api-key`,validator:n}=e;return new y({name:`@longzai-intelligence-auth/api-key`}).derive(async({request:e})=>{let r=e.headers.get(t)??e.headers.get(t.toLowerCase());if(!r)throw new p(`缺少 API Key`);let i=await n(r);if(!i)throw new f(`无效的 API Key`);return{auth:{userId:i.principalId,tenantId:i.tenantId??`default`,roles:i.roles,permissions:i.permissions,authMethod:`api-key`}}}).as(`scoped`)}function U(e){return async t=>{let n=e[t];return n?{principalId:n.principalId,tenantId:n.tenantId,roles:n.roles,permissions:n.permissions}:null}}function W(e){return{authMethod:`jwt`,userId:e.userId,tenantId:e.tenantId,roles:e.roles,permissions:e.permissions}}function G(e,t){return{authMethod:`api-key`,userId:e.principalId,tenantId:e.tenantId??t,roles:e.roles,permissions:e.permissions}}function K(e){return{algorithm:`HS256`,secret:e.secret,accessExpiresIn:e.accessExpiresIn,refreshExpiresIn:e.refreshExpiresIn}}function q(e,t,n){let r=[];return e&&r.push(e),t&&t.length>0&&r.push(...t),r.length>0?r:[new v(K(n??g()))]}function J(e,t){return t.some(t=>t.endsWith(`/*`)?e.startsWith(t.slice(0,-2)):e===t)}async function Y(e,t){for(let n of e)try{let e=await n.verifyAccessToken(t);if(e.success&&e.payload)return{success:!0,payload:e.payload}}catch{}return null}function X(e){let{verifier:t,verifiers:n,jwt:r,defaultTenantId:i=`default`,apiKeyValidator:a,apiKeyHeader:o=`x-api-key`,publicPaths:s=[]}=e,c=q(t,n,r);return new y({name:`@longzai-intelligence-auth/composite-auth`}).derive(async({request:e})=>{if(J(new URL(e.url).pathname,s))return{auth:null};let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(n){let e=await Y(c,n);if(e)return h.parse(e.payload),{auth:W({userId:e.payload.sub,tenantId:e.payload.tenantId??i,roles:e.payload.roles??[],permissions:e.payload.permissions??[]})}}if(a){let t=e.headers.get(o)??e.headers.get(o.toLowerCase());if(t){let e=await a(t);if(e)return{auth:G(e,i)}}}return{auth:null}}).as(`scoped`)}function Z(e){let{verifier:t,verifiers:n,jwt:r,defaultTenantId:i=`default`,apiKeyValidator:a,apiKeyHeader:o=`x-api-key`,publicPaths:s=[]}=e,c=q(t,n,r);return new y({name:`@longzai-intelligence-auth/required-composite-auth`}).derive(async({request:e})=>{if(J(new URL(e.url).pathname,s))return{auth:{authMethod:`jwt`,userId:``,tenantId:i,roles:[],permissions:[]}};let t=e.headers.get(`Authorization`),n=t?.startsWith(`Bearer `)?t.slice(7):null;if(n){let e=await Y(c,n);if(e)return h.parse(e.payload),{auth:W({userId:e.payload.sub,tenantId:e.payload.tenantId??i,roles:e.payload.roles??[],permissions:e.payload.permissions??[]})}}if(a){let t=e.headers.get(o)??e.headers.get(o.toLowerCase());if(t){let e=await a(t);if(e)return{auth:G(e,i)}}}throw Error(`认证失败:需要提供有效的 JWT Token 或 API Key`)}).as(`scoped`)}function ne(e){return e.headers.get(`x-forwarded-for`)?.split(`,`)[0]?.trim()??e.headers.get(`x-real-ip`)??`unknown`}function Q(e){let{limiter:t,logger:n}=e,r=e.keyGenerator??ne;return new y({name:`@longzai-intelligence-auth/rate-limit`}).derive(({request:e})=>({clientIp:r(e)})).derive(async({clientIp:e,request:r})=>{let i=new URL(r.url).pathname,a=`${e}:${i}`,o=await t.checkLimit(a);if(!o.allowed)throw n?.warn(`限流触发`,{clientIp:e,path:i}),new d;return{rateLimitRemaining:o.remaining}}).as(`global`)}function $(e={}){let{logger:n}=e;return new y({name:`@longzai-intelligence-auth/error-handler`}).onError(({code:e,error:r,set:i})=>{if(r instanceof t)return i.status=b(r),{code:r.code,message:r.message,...r.context&&Object.keys(r.context).length>0?{details:r.context}:{}};switch(e){case`VALIDATION`:return i.status=400,{code:`VALIDATION_ERROR`,message:`请求参数验证失败`,details:r.all.map(e=>({path:e.path,message:e.summary}))};case`NOT_FOUND`:return i.status=404,{code:`NOT_FOUND`,message:`未找到请求的资源`};case`PARSE`:return i.status=400,{code:`PARSE_ERROR`,message:`请求数据解析失败`};default:return n?.error(`未预期的错误`,{error:r instanceof Error?r.message:String(r),stack:r instanceof Error?r.stack:void 0}),i.status=500,{code:`INTERNAL_ERROR`,message:`服务器内部错误`}}}).as(`global`)}function re(e){let{logger:t}=e;return new y({name:`@longzai-intelligence-auth/logger`}).onRequest(({request:e})=>{t.info(`${e.method} ${e.url}`)}).onAfterResponse(({request:e,set:n})=>{t.info(`${e.method} ${e.url} ${n.status}`)}).onError(({request:e,error:n})=>{t.error(`${e.method} ${e.url} 请求错误`,{error:n instanceof Error?n.message:String(n)})}).as(`global`)}function ie(e){return new y({name:`@longzai-intelligence-auth/basic-preset`}).use(F({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,extendSchema:e.extendSchema})).use($({logger:e.logger}))}function ae(e){let t=e.apiKeyValidator?Z({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,apiKeyValidator:e.apiKeyValidator}):F({verifier:e.tokenVerifier,defaultTenantId:e.defaultTenantId,publicPaths:e.publicPaths,extendSchema:e.extendSchema}),n=new y({name:`@longzai-intelligence-auth/standard-preset`}).use(t).use(V({userRole:e.userRole}));return e.rateLimiter&&n.use(Q({limiter:e.rateLimiter,logger:e.logger})),n.use($({logger:e.logger}))}function oe(e){return e.headers.get(`x-forwarded-for`)?.split(`,`)[0]?.trim()??e.headers.get(`x-real-ip`)??void 0}function se(e){return e.headers.get(`user-agent`)??void 0}export{T as createApiKeyExtractor,H as createApiKeyPlugin,ie as createBasicPreset,w as createBearerExtractor,A as createBearerJwtVerifier,X as createCompositeAuthPlugin,C as createCookieExtractor,k as createCookieJwtVerifier,$ as createErrorHandlerPlugin,U as createInMemoryApiKeyValidator,F as createJwtVerifyPlugin,re as createLoggerPlugin,R as createOptionalJwtPlugin,Q as createRateLimitPlugin,V as createRbacPlugin,Z as createRequiredCompositeAuthPlugin,ae as createStandardPreset,S as createStaticTokenVerifier,oe as extractClientIp,se as extractUserAgent,b as mapDomainErrorToStatus};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@longzai-intelligence-auth/elysia",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"clean": "rimraf dist out .cache"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@longzai-intelligence-auth/core": "0.0.
|
|
40
|
-
"@longzai-intelligence-auth/jwt": "0.0.
|
|
39
|
+
"@longzai-intelligence-auth/core": "0.0.8",
|
|
40
|
+
"@longzai-intelligence-auth/jwt": "0.0.8",
|
|
41
41
|
"@longzai-intelligence/error": "^0.0.5",
|
|
42
42
|
"@elysiajs/bearer": "^1.3",
|
|
43
43
|
"zod": "^3.24"
|