Skip to content

拦截器与资源归属

这些拦截器补充或重试 FetchExchange。通过对应 request、response 或 error manager 的 .use(instance) 注册。配置器安装常见组合。

实际执行流程

  1. CoSecRequestInterceptor 设置应用/设备/请求头,以及解析得到的真值空间 ID。
  2. AuthorizationRequestInterceptor 保留已有 Authorization;否则检查会话所有权,access 过期且 refresh 有效时刷新,再注入受管理的 Bearer token。
  3. ResourceAttributionRequestInterceptor 在 URL 解析前填充租户/所有者路径参数,随后核心传输发送请求。
  4. AuthorizationResponseInterceptor 在正常状态校验前处理受管理凭据的 401。刷新后仅删除自己注入的陈旧凭据,并完整重跑 exchange 管线,最多一次。
  5. 剩余失败进入错误拦截器。Unauthorized 通过通知所有权守卫处理 401/RefreshTokenError;Forbidden 处理 403。回调都不会自动恢复失败请求。

request/response manager 按 order 排序,注册顺序本身不是执行契约。重跑管线可能生成新的 CoSec 请求 ID。调用者提供的 Authorization 不会替换或自动刷新。access 已过期而 refresh 不可用时仍可能附加 token,由服务端决定响应状态。

mermaid
sequenceDiagram
  autonumber
  participant App
  participant Fetcher
  participant Tokens
  participant Service
  App->>Fetcher: Request
  Fetcher->>Tokens: 读取受管理会话
  opt access 过期且 refresh 有效
    Tokens->>Service: POST refresh
    Service-->>Tokens: CompositeToken
  end
  Fetcher->>Service: 携带受管理 Authorization 的请求
  Service-->>Fetcher: Response
  opt 受管理请求的 401,尚未重试
    Fetcher->>Tokens: 刷新同一会话
    Tokens-->>Fetcher: 当前 token 或错误
    Fetcher->>Service: 重跑 exchange 一次
    Service-->>Fetcher: 重试响应
  end
  Fetcher-->>App: 提取结果或错误

拦截器参数与结果

导出构造选项intercept(exchange)
CoSecRequestInterceptor / CoSecRequestOptions必填 appId、deviceIdStorage;spaceIdProvider 默认 NoneSpaceIdProviderPromise<void>;覆盖应用/设备/请求头;仅为真值 ID 写空间头;存储/provider 失败传播
AuthorizationRequestInterceptor / AuthorizationInterceptorOptions必填 tokenManager(JwtTokenManagerCapable)Promise<void>;保留显式 Authorization,需要时刷新受管理 token
AuthorizationResponseInterceptor同 AuthorizationInterceptorOptionsPromise<void>;仅 401、匹配受管理凭据,最多 AUTHORIZATION_RESPONSE_MAX_RETRY=1
ResourceAttributionRequestInterceptor / ResourceAttributionOptions必填 tokenStorage;tenantId='tenantId'、ownerId='ownerId' 是占位符名称void;从解码的 access payload 取 tenantId/sub;仅匹配模板且当前路径值为假值时填充
UnauthorizedErrorInterceptor / options必填 onUnauthorized,返回 void 或 Promise<void>Promise<void>;跳过 RefreshSessionChangedError 及重复/过时通知;回调错误传播
ForbiddenErrorInterceptor / options必填 onForbidden,返回 Promise<void>Promise<void>;仅 response.status=403 时执行回调;回调错误传播

IGNORE_REFRESH_TOKEN_ATTRIBUTE_KEYIgnore-Refresh-Token。只要属性存在(即使值为 false),就禁用主动/401 自动刷新。它不阻止 Authorization 注入,也不禁用普通 HTTP 状态错误。

设备与空间选择

DeviceIdStorage(options={})SpaceIdStorage(options={}) 继承 KeyStorage<string>。选项为部分 KeyStorageOptions,每个类都强制使用自己的 identity serializer。默认键分别是 cosec-device-idcosec-space-id,默认广播总线的 serial delegate 名称取实际 key。存储选择继承自 KeyStorage,可注入事件总线/存储;清理遵循 KeyStorage

DeviceIdStorage.generateDeviceId(): string 调用导出的 idGenerator,但不存储结果。getOrCreate(): string 返回已有真值 ID,否则生成并存储。IdGenerator.generateId(): stringNanoIdGenerator 使用 nanoid 实现,idGenerator 是共享实例。

SpaceIdProvider.resolveSpaceId(exchange): string | null 为同步方法。NoneSpaceIdProvider 始终返回 null。DefaultSpaceIdProvider({ spacedResourcePredicate, spaceIdStorage }) 两者必填,调用 SpacedResourcePredicate.test(exchange): boolean,仅匹配时返回已存空间值。没有你的 predicate/storage 就不会自行从 URL 或 token 推断空间。

常量与鉴权数据

导出族
COSEC_REQUEST_INTERCEPTOR_NAME/ORDERCoSecRequestInterceptor / Number.MIN_SAFE_INTEGER + DEFAULT_INTERCEPTOR_ORDER_STEP
AUTHORIZATION_REQUEST_INTERCEPTOR_NAME/ORDERAuthorizationRequestInterceptor / COSEC_REQUEST_INTERCEPTOR_ORDER + DEFAULT_INTERCEPTOR_ORDER_STEP
AUTHORIZATION_RESPONSE_INTERCEPTOR_NAME/ORDERAuthorizationResponseInterceptor / Number.MIN_SAFE_INTEGER + 1000
RESOURCE_ATTRIBUTION_REQUEST_INTERCEPTOR_NAME/ORDERResourceAttributionRequestInterceptor / URL_RESOLVE_INTERCEPTOR_ORDER - DEFAULT_INTERCEPTOR_ORDER_STEP
UNAUTHORIZED_ERROR_INTERCEPTOR_NAME/ORDERUnauthorizedErrorInterceptor / 0
FORBIDDEN_ERROR_INTERCEPTOR_NAME/ORDERForbiddenErrorInterceptor / 0
DEFAULT_COSEC_DEVICE_ID_KEYDEFAULT_COSEC_SPACE_ID_KEYcosec-device-id、cosec-space-id
CoSecHeaders 静态字段DEVICE_ID=CoSec-Device-Id、APP_ID=CoSec-App-Id、SPACE_ID=CoSec-Space-Id、AUTHORIZATION=Authorization、REQUEST_ID=CoSec-Request-Id
ResponseCodesUNAUTHORIZED=401、FORBIDDEN=403

AuthorizeResult{ authorized:boolean, reason:string }AuthorizeResults 含 ALLOW(true、'Allow')、EXPLICIT_DENY('Explicit Deny')、IMPLICIT_DENY('Implicit Deny')、TOKEN_EXPIRED('Token Expired')、TOO_MANY_REQUESTS('Too Many Requests');除 ALLOW 外 authorized 均为 false。它们是结果对象,不是本地策略引擎或服务端状态码映射器。

完整空间配置

ts
import { Fetcher } from '@ahoo-wang/fetcher';
import {
  CoSecConfigurer,
  DefaultSpaceIdProvider,
  SpaceIdStorage,
  TokenStorage,
  DeviceIdStorage,
} from '@ahoo-wang/fetcher-cosec';
import { InMemoryStorage } from '@ahoo-wang/fetcher-storage';
import { SerialTypedEventBus } from '@ahoo-wang/fetcher-eventbus';

const spaces = new SpaceIdStorage({
  storage: new InMemoryStorage(),
  eventBus: new SerialTypedEventBus('example-space'),
});
spaces.set('workspace-1');
const provider = new DefaultSpaceIdProvider({
  spaceIdStorage: spaces,
  spacedResourcePredicate: {
    test: exchange => exchange.request.url.startsWith('/projects'),
  },
});
const fetcher = new Fetcher({ baseURL: 'https://api.example.com' });
const cosec = new CoSecConfigurer({
  appId: 'example-app',
  spaceIdProvider: provider,
  tokenStorage: new TokenStorage({
    storage: new InMemoryStorage(),
    eventBus: new SerialTypedEventBus('example-token'),
  }),
  deviceIdStorage: new DeviceIdStorage({
    storage: new InMemoryStorage(),
    eventBus: new SerialTypedEventBus('example-device'),
  }),
});
cosec.applyTo(fetcher);
// 构造配置本身不发送请求。
spaces.destroy();
cosec.tokenStorage.destroy();
cosec.deviceIdStorage.destroy();

AuthorizationInterceptorOptionspackages/cosec/src/authorizationRequestInterceptor.ts:29

AUTHORIZATION_REQUEST_INTERCEPTOR_NAMEpackages/cosec/src/authorizationRequestInterceptor.ts:31

AUTHORIZATION_REQUEST_INTERCEPTOR_ORDERpackages/cosec/src/authorizationRequestInterceptor.ts:33

AuthorizationRequestInterceptorpackages/cosec/src/authorizationRequestInterceptor.ts:46

AUTHORIZATION_RESPONSE_INTERCEPTOR_NAMEpackages/cosec/src/authorizationResponseInterceptor.ts:31

AUTHORIZATION_RESPONSE_INTERCEPTOR_ORDERpackages/cosec/src/authorizationResponseInterceptor.ts:38

AUTHORIZATION_RESPONSE_MAX_RETRYpackages/cosec/src/authorizationResponseInterceptor.ts:47

AuthorizationResponseInterceptorpackages/cosec/src/authorizationResponseInterceptor.ts:66

CoSecRequestOptionspackages/cosec/src/cosecRequestInterceptor.ts:57

COSEC_REQUEST_INTERCEPTOR_NAMEpackages/cosec/src/cosecRequestInterceptor.ts:83

COSEC_REQUEST_INTERCEPTOR_ORDERpackages/cosec/src/cosecRequestInterceptor.ts:104

IGNORE_REFRESH_TOKEN_ATTRIBUTE_KEYpackages/cosec/src/cosecRequestInterceptor.ts:131

CoSecRequestInterceptorpackages/cosec/src/cosecRequestInterceptor.ts:215

DEFAULT_COSEC_DEVICE_ID_KEYpackages/cosec/src/deviceIdStorage.ts:25

DeviceIdStorageOptionspackages/cosec/src/deviceIdStorage.ts:28

DeviceIdStoragepackages/cosec/src/deviceIdStorage.ts:35

IdGeneratorpackages/cosec/src/idGenerator.ts:16

NanoIdGeneratorpackages/cosec/src/idGenerator.ts:24

idGeneratorpackages/cosec/src/idGenerator.ts:35

ResourceAttributionOptionspackages/cosec/src/resourceAttributionRequestInterceptor.ts:27

RESOURCE_ATTRIBUTION_REQUEST_INTERCEPTOR_NAMEpackages/cosec/src/resourceAttributionRequestInterceptor.ts:45

RESOURCE_ATTRIBUTION_REQUEST_INTERCEPTOR_ORDERpackages/cosec/src/resourceAttributionRequestInterceptor.ts:50

ResourceAttributionRequestInterceptorpackages/cosec/src/resourceAttributionRequestInterceptor.ts:58

SpaceIdProviderpackages/cosec/src/spaceIdProvider.ts:70

NoneSpaceIdProviderpackages/cosec/src/spaceIdProvider.ts:126

DEFAULT_COSEC_SPACE_ID_KEYpackages/cosec/src/spaceIdProvider.ts:137

SpaceIdStorageOptionspackages/cosec/src/spaceIdProvider.ts:172

SpaceIdStoragepackages/cosec/src/spaceIdProvider.ts:213

SpacedResourcePredicatepackages/cosec/src/spaceIdProvider.ts:297

SpaceIdProviderOptionspackages/cosec/src/spaceIdProvider.ts:326

DefaultSpaceIdProviderpackages/cosec/src/spaceIdProvider.ts:383

CoSecHeaderspackages/cosec/src/types.ts:20

ResponseCodespackages/cosec/src/types.ts:28

AuthorizeResultpackages/cosec/src/types.ts:57

AuthorizeResultspackages/cosec/src/types.ts:65

UNAUTHORIZED_ERROR_INTERCEPTOR_NAMEpackages/cosec/src/unauthorizedErrorInterceptor.ts:24

UNAUTHORIZED_ERROR_INTERCEPTOR_ORDERpackages/cosec/src/unauthorizedErrorInterceptor.ts:31

UnauthorizedErrorInterceptorOptionspackages/cosec/src/unauthorizedErrorInterceptor.ts:36

UnauthorizedErrorInterceptorpackages/cosec/src/unauthorizedErrorInterceptor.ts:76

FORBIDDEN_ERROR_INTERCEPTOR_NAMEpackages/cosec/src/forbiddenErrorInterceptor.ts:21

FORBIDDEN_ERROR_INTERCEPTOR_ORDERpackages/cosec/src/forbiddenErrorInterceptor.ts:27

ForbiddenErrorInterceptorOptionspackages/cosec/src/forbiddenErrorInterceptor.ts:32

ForbiddenErrorInterceptorpackages/cosec/src/forbiddenErrorInterceptor.ts:113

基于 Apache License 2.0 发布。