status: propose created: 2026-07-31 complexity: 🔴复杂
客户需求(20260728需求)中 API-01~07(外部机器身份 API 底座)阻断差评流程 F1/NR-04 外部建单。经代码核查,现有 Capability 平台(AI 中枢)已具备机器身份、授权、审计、OAuth2.1、字段白名单等核心底座,但只有 MCP 出口,没有面向普通外部系统的 REST 出口,也没有管理控制台。
本变更目标(一期范围):
POST /openapi/v1/capabilities/{capabilityCode}/invoke,形成"认证→防重放→授权→限流→幂等→Schema 校验→执行→统一响应→审计"完整闭环。required_actor_type(SERVICE/USER/BOTH),身份类型校验前移到网关授权阶段;USER 委托 Token 在 REST 网关复用现有 ExecutionIdentityContextHolder 链路。USER_DELEGATION/SERVICE/HYBRID;纯用户委托客户端不再绑定 Forge 服务账号和固定组织。issuer + subject 自动映射现有用户并签发短期 USER Token。完成后可验证效果:外部系统使用机器客户端凭据(OAuth 或签名模式),调用已授权的 BUSINESS_ACTION 能力(如差评建单),带 Idempotency-Key 重试不产生重复单据;持 USER 委托 Token 可通过网关调用 FLOW_ACTION 能力完成流程审批(办理人校验生效);调用记录可在控制台查询;机器身份调用 requiredActorType=USER 的能力被网关直接拒绝。
forge-plugin-mcp/config/ForgeMcpServerConfiguration.java,Streamable HTTP 单端点 /mcp,默认 FORGE_MCP_ENABLED=false。forge-plugin-capability-identity/token/CapabilityTokenController.java(/oauth2/token、/oauth2/revoke),授权码+PKCE 见 oauth/CapabilityAuthorizationController.java。forge-plugin-capability-control-plane/controller/CapabilityCatalogController.java(/ai/capability)、CapabilityClientController.java(/ai/capability/client)、CapabilityGrantController.java(/ai/capability/grant),权限点 ai:capability:* 已由 V1.0.21 落库并授予 admin。forge-starter-auth/config/SaTokenConfig.java,已有 /mcp、/oauth2/*、/openapi/v1/jobs/** 放行先例。CapabilityAccessTokenService.authenticate() 校验 fdu_ 短期 Token(HMAC 哈希存储、audience、scope、credential_version),loadCurrentUser() 每次请求实时从用户目录重建 LoginUser(校验状态/租户/组织/强制改密),返回 AuthenticatedCapabilityIdentity(principal, loginUser)。forge-starter-core/context/ExecutionIdentityContextHolder(ThreadLocal)承载 ExecutionIdentity(loginUser, actorType, ...);异步透传由 TenantBusinessDataSourceTaskDecorator 完成;跨服务流程调用由 SaTokenFlowTokenProvider 铸造短期委托会话,FlowDelegationSessionVerifier 校验。FlowActionExecutionAdapter.requireIdentity() 强制 actorType=USER,机器身份调流程动作抛 USER_DELEGATION_REQUIRED——但这个约束目前在执行层兜底,网关/授权层无 actorType 概念。ai_capability/ai_capability_version/ai_capability_client/ai_capability_grant/ai_capability_invocation_log(V1.0.21)、ai_capability_access_token(V1.0.22)。ai_capability_invocation_log 已有 UNIQUE (tenant_id, request_id)。forge-plugin-job/manager/JobApiRateLimitManager.java(Redisson RRateLimiter,按 keyId+操作分钟级,Redis 不可用失败关闭 503)、JobApiIdempotencyManager.java(Idempotency-Key 格式校验 + SHA-256 哈希 + Redisson 锁 + DB 唯一约束回查)。job-api-token.vue 是成熟的凭据管理页参考(创建/轮换/吊销/一次性展示/调用说明)。ai_capability_client.key_hash 是 HMAC-SHA256 单向哈希,服务端无法还原密钥原文,不能直接用于请求签名验签。签名模式必须新增可逆加密存储的独立签名密钥(KEK 加密,复用 forge-starter-crypto 体系),不能改动现有 Bearer 凭据的哈希语义。ai_capability_grant.field_policy 字段白名单已被 secure-actions 链消费,REST 网关须走同一策略入口,不得旁路。invocation_log 不存响应体(安全设计),需新增专用幂等表。{code,message,requestId,timestamp,data} + 审计入库)X-Forge-App-Id + X-Forge-Timestamp + X-Forge-Nonce + X-Forge-Signature → 验签 + 时间窗 ±5 分钟 + nonce Redis 一次性校验 → 得到 SERVICE 身份)Authorization: Bearer fdu_... → CapabilityAccessTokenService.authenticate() → SERVICE 或 USER 身份)required_actor_type 元数据(发布时声明 → 网关授权阶段校验身份类型 → 不匹配返回 403 ACTOR_TYPE_NOT_ALLOWED)Idempotency-Key,命中幂等返回首次响应快照 + idempotentHit=true)/ai/capability/* 接口;客户端页新增签名密钥管理)USER_DELEGATION 默认且不绑定账号;SERVICE/HYBRID 才要求服务账号与组织)/oauth2/userinfopublish_status=PUBLISHED、enabled=1 且对当前客户端存在 ENABLED 未过期 grant 的能力;版本按 grant 的 version_strategy 解析。一期开放能力类型不设限(含 FLOW_ACTION),由 required_actor_type + grant 控制边界。required_actor_type=USER 的能力(流程审批类)拒绝签名模式和 SERVICE Bearer;SERVICE 的能力拒绝 USER 委托调用;BOTH 均可。存量能力回填默认值:FLOW_ACTION → USER,其余 → SERVICE。behavior != READ_ONLY)必须携带 Idempotency-Key(8-128 位 [A-Za-z0-9._:-]),缺失返回 400 missing_idempotency_key。service_user_id/active_org_id 或委托 Token 的 actor_user_id),禁止从 Header/Body 接受调用方指定。appId\ntimestamp\nnonce\nMETHOD\npath\nsha256(body),HMAC-SHA256,常量时间比较。ai_capability_invocation_log,不保存请求/响应原文。USER_DELEGATION 客户端的 service_user_id/active_org_id 必须为空,只允许 OAUTH,不允许 HMAC 签名和 client_credentials;SERVICE/HYBRID 继续要求有效服务账号和组织。none、共享密钥和调用方指定 JWK 地址。issuer + sub 作为稳定身份。首次映射按配置的手机号 claim 在指定租户精确匹配现有 Forge 用户,姓名仅做一致性校验;手机号/姓名不能脱离 JWT 单独认证。IUserLoadService 重新验证用户租户成员、组织成员、状态、角色和权限;不允许外围系统直接指定最终租户或组织。| 操作 | 表名 | 字段/索引 | 说明 |
|---|---|---|---|
| 新增列 | ai_capability | required_actor_type varchar(16) NOT NULL DEFAULT 'SERVICE' |
能力要求的调用主体类型;存量 FLOW_ACTION 回填 USER |
| 新增列 | ai_capability_version | required_actor_type varchar(16) NOT NULL DEFAULT 'SERVICE' |
版本快照同步 |
| 新增列 | ai_capability_client | auth_modes varchar(64) NOT NULL DEFAULT 'OAUTH' |
允许的认证模式:OAUTH / SIGNATURE / 两者 |
| 新增列 | ai_capability_client | signing_key_cipher varchar(512) DEFAULT NULL、signing_key_version int DEFAULT NULL |
KEK 加密的签名密钥密文及密钥版本 |
| 新增表 | ai_capability_openapi_idempotency | (id, tenant_id, client_id, capability_id, idempotency_key_hash, request_id, response_snapshot json, expires_at, 标准审计列, del_flag);UNIQUE(tenant_id, client_id, capability_id, idempotency_key_hash, logic_delete_active) |
幂等记录 + 首次响应快照(24h TTL 清理) |
| 新增数据 | sys_dict_type / sys_dict_data | ai_capability_actor_type、ai_capability_auth_mode |
字典,tenant_id=1,NOT EXISTS 防重复 |
| 新增数据 | sys_resource / sys_role_resource | 新建"开放平台"一级目录(resource_type=1)+ 其下 4 个菜单(resource_type=2) | 权限点复用 V1.0.21 已有 ai:capability:*,仅补目录与菜单路由 |
| 新增列 | ai_capability_client | actor_mode varchar(24) NOT NULL DEFAULT 'HYBRID';service_user_id/active_org_id 改为可空 |
存量客户端兼容为 HYBRID;新建 USER_DELEGATION 不绑定账号 |
| 新增表 | ai_capability_external_identity | (issuer_hash, subject_hash, user_id, provider_code, last_authenticated_at, 标准审计列, del_flag) |
受信外部身份首次自动映射,唯一键使用租户 + issuer/sub 哈希 + 主键墓碑 |
| 修改列 | ai_capability_access_token / ai_capability_flow_action_log | service_user_id 改为可空 |
USER_DELEGATION 没有伪造的服务账号;SERVICE 身份仍强制非空 |
| 新增数据 | sys_dict_type / sys_dict_data | ai_capability_client_actor_mode |
用户委托/服务身份/混合模式字典,tenant_id=1,NOT EXISTS |
脚本:V1.0.74__capability_open_gateway.sql(防重复保护、tenant_id=1、显式列名)。
| 操作 | 接口 | 方法 | 变更内容 |
|---|---|---|---|
| 新增 | /openapi/v1/capabilities/:capabilityCode/invoke |
POST | 统一能力调用入口(外部,Sa-Token 白名单放行后自行鉴权) |
| 新增 | /ai/capability/client/signing-key/rotate/:id |
POST | 轮换签名密钥,@ApiEncrypt 一次性返回明文 |
| 修改 | /ai/capability/publish |
POST | CapabilityPublishDTO 增加 requiredActorType |
| 修改 | /ai/capability/client/add |
POST | CapabilityClientCreateDTO 增加 authModes;选择 SIGNATURE 时一次性返回签名密钥 |
| 新增 | /ai/capability/invocation/page |
GET | 调用日志分页查询(权限点 ai:capability:invocation:query 已存在) |
| 修改 | /ai/capability/client/add |
POST | 增加 actorMode;USER_DELEGATION 时服务账号/组织可空且禁止 SIGNATURE |
| 修改 | /oauth2/token |
POST | 增加 RFC 8693 token-exchange grant,接收受信 OIDC JWT 并签发 USER Token |
| 新增 | /oauth2/userinfo |
GET | Bearer Token 返回当前 USER 身份、租户和活动组织信息 |
| 新增 | /ai/capability/:id/openapi |
GET | 下载当前已发布能力版本的 OpenAPI 3.1 JSON 文档 |
统一响应(网关):{"code":"SUCCESS|错误码","message":"...","requestId":"...","timestamp":epochMillis,"data":{}};错误码集合:UNAUTHORIZED/REPLAY_REJECTED/FORBIDDEN/ACTOR_TYPE_NOT_ALLOWED/RATE_LIMITED/SCHEMA_INVALID/CONFLICT/INTERNAL_ERROR。
forge-plugin-capability-open-gateway(新插件:网关 Controller、认证过滤链、编排服务)、forge-starter-openapi-security(通用限流/幂等/防重放组件)。SaTokenConfig(白名单追加 /openapi/v1/capabilities/**)、application.yml(forge.capability.open-gateway.* 配置组,默认关闭)。forge-admin-ui/src/views/ai/capability/ 4 个页面 + src/api/ai/capability.js。/openapi/v1/jobs 契约(迁移复用组件列为后续变更);MCP 链路;Flowable。⚠️ 本变更属于权限边界扩展(将内部能力开放给外部系统调用),必须人工审查。
FORGE_CAPABILITY_OPEN_GATEWAY_ENABLED=false)、失败关闭策略、能力需显式授权、HIGH 风险禁止授权延续。required_actor_type=USER 能力只接受用户委托 Token。response_snapshot 可能含敏感字段。缓解:24h TTL 清理任务物理清理(属留存清理场景,允许物理删除)、快照只存网关统一响应体、控制台不展示快照内容。input_schema 校验并按 grant field_policy 过滤,禁止直通。issuer + sub,Forge 用户状态和组织每次实时校验。READ_ONLY + BUSINESS_ACTION?→ 确认:不限定,FLOW_ACTION 的 USER 委托 REST 调用放到一期(网关不按能力类型设限,端到端测试须覆盖 USER 委托审批链路)。issuer + sub 映射。auth_modes 白名单启用。ExecutionIdentityContextHolder.open(identity) 包裹执行,下游租户/数据权限/审计零改动。required_actor_type 拒绝,比执行层兜底(USER_DELEGATION_REQUIRED)提前失败;执行层约束保留作为纵深防御。SaTokenFlowTokenProvider 铸造委托会话与 FLOW_TASK_ASSIGNEE_MISMATCH 办理人校验,网关侧不重复实现流程语义。fdu_ USER Token,不引入手机号+姓名自报认证协议。crypto.properties;生产多实例使用共享 Secret Manager 显式覆盖,关闭 Bootstrap 后缺失配置继续拒绝启动。| Task | 状态 | 实际改动文件 | 备注 |
|---|