主题
02 三角接线:HiMarket × Higress × Nacos × 企业 SSO
一句话:三角接线的实质是“引用而非复制”:HiMarket 只在 ProductRef 里记“能力对应 Higress 的哪条路由、Nacos 的哪份配置”,OIDC 把企业 IdP 的 subject 映射成 Developer,配置面管关系与授权、流量面管放行与计量、注册面管内容事实;边界是三层各自演进且互不校验,路由改名、5 分钟同步滞后、ID Token 未验签、内网域被过滤成空地址,任一错位都先在消费端调用时暴露。
接 01 篇《HiMarket 底座与五类市场》。01 篇回答了“HiMarket 里面有什么”(六层架构、当前快照 28 个 Controller、API Product 模型),本篇回答“HiMarket 怎么跟 Higress、Nacos、企业 SSO 长在一起”——它是怎么融入企业生态的。结论均来自本地源码(
himarket-server,commit3a63fc5)并标注到类/方法级。
一、一句话定位:HiMarket 不是孤岛,是三层结构
HiMarket 对外呈现为"一个市场门户",但它的骨架是三层:
| 层 | 组件 | 角色 | 一句话 |
|---|---|---|---|
| 市场/门户层 | HiMarket(himarket-server + admin + frontend) | 元信息 + 关系 + 契约 | 管"有什么、谁能用、授权范围与计量事实"——不跑业务流量;凭证签发与注入在数据面 Broker |
| 运行时/网关层 | Higress(AI 网关) | 流量 + 执行 + 治理 | 管"调用怎么放行、转发到哪、限流计量"——承载业务流量 |
| 内容/注册层 | Nacos(AI 内容注册中心) | 内容 + 规格 + 地址 | 管"MCP Server 配置、Agent 规格、Skill 工具定义、Worker 地址"——能力的事实来源 |
外加一个身份维度:企业 IdP(飞书/企微/钉钉/Azure AD/Keycloak 等)通过 OIDC 与 HiMarket 打通,解决"人是谁、能进哪个门户"。
谁不干什么,比谁干什么更重要:
- HiMarket 不直接转发调用——流量走 Higress;
- Nacos 不直接进业务链路——它被 HiMarket 拉取/同步,产物是元数据与配置;
- Higress 不存市场关系——谁订阅了什么产品、授权范围是什么,在市场 DB;消费者凭证与上游服务凭证分属不同域,上游密钥由 Vault/KMS 管理。
二、三角关系源码证据链(已实读)
2.1 关系的中枢:ProductRef(产品↔能力引用)
一切接线围绕 Product(可售能力) 和 ProductRef(引用) 展开。一个 Product 通过 ProductRef 指向两类外部事实:Higress 上的路由 或 Nacos 里的配置。
ProductRefResult(himarket-server dto/result/product/ProductRefResult.java):
java
public class ProductRefResult {
private String productId;
private SourceType sourceType; // API_DEFINITION / GATEWAY / NACOS 等
private String gatewayId;
private APIGRefConfig apigRefConfig;
private APIGRefConfig adpAIGatewayRefConfig;
private APIGRefConfig apsaraGatewayRefConfig;
private HigressRefConfig higressRefConfig; // 引用 Higress 路由
private String nacosId; // 引用 Nacos 实例
private NacosRefConfig nacosRefConfig; // Nacos 里的目标
}重要校正:
ProductRefResult不包含mcpConfig、agentConfig、modelConfig,也不包含凭证。GET /products/{id}/ref返回的是引用元数据,不是可直接调用的连接配置。
两种引用配置的字段(himarket-dal support/product/):
java
// HigressRefConfig:指向 Higress 上已存在的 AI 路由
public class HigressRefConfig {
private String routeName; // HTTP 路由名(通用)
private String mcpServerName; // Higress MCP Server 名
private String modelRouteName; // 模型路由名(MODEL_API 用)
}
// NacosRefConfig:指向 Nacos 里的 MCP/Agent 配置
public class NacosRefConfig {
private String mcpServerName; // MCP Server(MCP_SERVER 用)
private String agentName; // Agent(AGENT_API 用)
// + namespaceId / group 等寻址信息
}结论:HiMarket 的"关联"是一个引用模型——Product 不复制能力,只记录"能力在哪(Higress 路由 / Nacos 配置)"。这就是契约化接入的根:满足引用契约即可被市场化管理,无需重开发。
2.2 HiMarket → Nacos:能力内容的事实来源
| 类 | 职责 | 证据 |
|---|---|---|
NacosController + NacosServiceImpl | Nacos 实例导入/管理(地址、账号、缓存客户端) | NacosInstanceRepository 持久化;AiMaintainerService 按实例缓存 |
McpConfigSyncHelper#fetchRemoteConfig | 按 nacosId + NacosRefConfig 从 Nacos 拉取 MCP 配置 | nacosService.fetchMcpConfig(param.getNacosId(), nacosRef)(service/mcp/McpConfigSyncHelper.java:169) |
SkillWorkerMetadataSyncTask | 每 5 分钟定时从 Nacos 同步 Skill / Worker 元数据,生成/更新 Product 草稿 | @Scheduled(fixedDelay = 300_000)(service/task/SkillWorkerMetadataSyncTask.java:53),使用 Nacos AI SDK 的 SkillSummary / AgentSpecSummary |
ProductServiceImpl | 创建 Skill/Worker 类产品时取默认 Nacos 实例 | nacosService.getDefaultNacosInstance()(service/impl/ProductServiceImpl.java:203) |
NacosServiceImpl | 连接参数:PropertyKeyConst.SERVER_ADDR/NAMESPACE/USERNAME/PASSWORD,默认 context path nacos | service/impl/NacosServiceImpl.java |
Nacos 在 HiMarket 里的三个用途(对应三类能力内容):
- MCP Server 配置:Nacos 里登记的 MCP 服务(域名/路径/凭证)→
fetchMcpConfig拉成McpConfigResult; - Agent 规格:Nacos AI 模块的 Agent 定义 →
fetchAgentConfig拉成 agent 配置; - Skill / Worker 元数据:定时任务批量同步到市场(Skill 工具规格、Worker 执行体地址)。
2.3 HiMarket → Higress:运行时网关的编排者
| 类 | 职责 | 证据 |
|---|---|---|
GatewayController + GatewayService | 导入/管理网关实例(Higress 控制台地址、账号、域名) | Gateway 实体 |
HigressOperator(service/gateway/HigressOperator.java) | 通过 Higress 控制台 API 操作网关:拉取 AI 路由、MCP 凭证、域名 | fetchAIRoute(gateway, higressRefConfig.getModelRouteName())(:273)、fetchMcpCredential(gateway, mcpServerName)(:320) |
McpConfigSyncHelper | 发布/关联时把 MCP 配置与 Higress 侧对齐 | 引用 GatewayService + NacosService |
关键机制:HiMarket 不是替 Higress 建路由,而是引用 Higress 上已存在的路由(mcpServerName / modelRouteName 是 Higress 侧的命名)。生产环境应发布一个稳定产品端点,再由配置发布器映射到目标路由;不能把 Nacos 中的临时地址直接暴露给消费端。
2.4 消费端拿到的“连接描述”:McpConfigResult.toTransportConfig()
HiMarket 内的 toTransportConfig() 从 mcpServerConfig.domains 拼出连接地址,当前源码逻辑如下(简化):
java
public McpTransportConfig toTransportConfig() {
// 过滤 intranet 域,取公网域名
DomainResult domain = mcpServerConfig.getDomains().stream()
.filter(d -> !"intranet".equalsIgnoreCase(d.getNetworkType()))
.findFirst().orElse(null);
String baseUrl = scheme + "://" + domain + (port > 0 ? ":" + port : "");
String url = baseUrl + (path.startsWith("/") ? path : "/" + path);
return McpTransportConfig.builder()
.mcpServerName(mcpServerName)
.transportMode(transportMode) // streamable_http / sse
.url(url)
.build();
}校正三点:
- 该对象只含
mcpServerName / transportMode / url,不含 tools 白名单,也不含凭证。调用头由消费端的CredentialContext另行注入。 - 源码会过滤
intranet域并取第一个非内网域;企业私有部署若只有内网地址,会得到空配置。生产实现必须显式配置“投递域名”,不能沿用该默认选择。 GET /products/{id}/ref返回的是ProductRefResult(引用元数据),不是McpTransportConfig。不能把两者混为“公开获取连接配置”。
因此,HiMarket 的契约落点是“引用 + 稳定产品端点 + 订阅授权”,不是“把上游连接和密钥打包给客户端”。凭证应由网关或凭证中介在调用时注入。
三、端到端数据流(发布 → 订阅 → 消费)
四、企业 SSO 融入:OIDC 身份链路(已实读源码)
4.1 HiMarket 的身份形态:OIDC Client(对接企业 IdP)
HiMarket 不是自建身份库对外发身份,而是对接企业既有的 OIDC Provider。开发者(企业员工)用企业账号登录开发者门户。
OidcController(controller/OidcController.java)三个端点:
text
GET /developers/oidc/providers → 列出可用 IdP(provider/displayName/图标)
GET /developers/oidc/authorize?provider=xxx&apiPrefix=/api/v1
→ 302 重定向到企业 IdP 授权页
GET /developers/oidc/callback?code=xxx&state=yyy
→ 换 token → 绑定 Developer → 返回 AuthResult4.2 Provider 配置:挂在 Portal 上(多租户维度)
OidcServiceImpl.findOidcConfig()(:191)——OidcConfig 存在 Portal 的 PortalSettingConfig 里:
java
private OidcConfig findOidcConfig(String provider) {
PortalResult portal = portalService.getPortal(contextHolder.getPortal());
List<OidcConfig> oidcConfigs = portal.getPortalSettingConfig().getOidcConfigs();
// 匹配 provider 且 enabled==true
}企业生态含义:每个租户(企业/部门)可以配自己的 IdP 集合。一个 Portal = 一个企业 = 一套 SSO。OidcConfig 字段:provider / displayName / enabled / clientId / clientSecret / authCodeConfig(tokenEndpoint, userInfoEndpoint, redirectUri 规则) / 域名白名单。
4.3 授权码流程实现(OidcServiceImpl)
text
1. buildAuthorizationUrl() → 构造 IdP 授权 URL(client_id + redirect_uri + state)
2. state = Base64(JSON{provider, apiPrefix, nonce, timestamp}) ← 防 CSRF + 记录登录目标
3. handleCallback() → 校验 state(10 分钟有效)→ requestToken(code) → getUserInfo
4. getUserInfo() → 优先解析 ID Token(验 exp);缺失则 fallback UserInfo endpoint
5. 身份绑定 → DeveloperServiceImpl.findByProviderAndSubject(provider, subject)
→ 存在即登录,不存在则按自动注册策略建 Developer
6. 返回 AuthResult → HiMarket 自签 token(TokenService),后续 API 用4.4 生产注意(源码直读发现的坑,已在文档里记录)
| 项 | 源码状态 | 生产要求 |
|---|---|---|
| ID Token 签名校验 | // TODO: Verify the ID token signature with the provider JWK set.(OidcServiceImpl:310) | 必须启用 JWK 验签(对接企业 IdP 的 discovery 端点拉 jwks_uri) |
| state 有效期 | 10 分钟(:227) | 合理;apiPrefix 需与 redirect_uri 白名单联动校验 |
| redirect_uri | buildRedirectUri(request, authCodeConfig) 动态拼 | 生产必须按 IdP 侧白名单严格配置,防 open redirect |
| 自动注册 | findByProviderAndSubject 不存在时自动建 Developer | 需按企业策略开关:仅 SSO 登录 vs 需管理员审批入租户 |
五、融入企业生态的整体架构(含我们平台的整合位)
要点(对应 07-32 集成接线设计):
- HiMarket = 人类入口与市场控制面:市场关系、订阅、审批与目录在这里;它管“谁能用什么”,但不承载业务流量、也不保管上游长期密钥;
- Higress = 运行时出口:业务流量唯一出口,限流/计量在网关执行(07-32 接缝 4、5 的落点);
- AuthZ/Credential Broker = 授权与凭证中介:校验订阅、工具白名单与配额,注入上游短期凭证;
- Nacos = 内容事实源:MCP/Agent/Skill/Worker 的配置与元数据从这里来(07-32 接缝 1、2 的落点);
- OIDC = 身份映射(接缝 3):企业 IdP 的 subject ↔ HiMarket Developer ↔(未来)agentscope-service 的 user,三层身份映射;
- 我们体系的整合位:消费端(qwenpaw 实例 / agentscope 执行体)作为 MCP/HTTP 客户端调用稳定产品端点,只持有平台凭证,不持有上游密钥。
六、待实证清单(对应 #18 接线,随部署推进逐项销项)
| # | 实证项 | 方法 | 状态 |
|---|---|---|---|
| 1 | HiMarket 最小集部署(mysql+nacos+server+admin+frontend+sandbox) | compose 起栈 | ✅(未含 Higress) |
| 2 | Nacos 登记 + 默认实例识别 | 管理端登记 → getDefaultNacosInstance 可查 | ✅ |
| 3 | MCP Server 从 Nacos 拉配置(fetchMcpConfig) | 创建 MCP 产品 → 检查 McpConfigResult 内容 | ⏳ |
| 4 | Higress 路由对齐(fetchAIRoute/fetchMcpCredential) | 导入 Higress → Link MODEL_API → 检查路由 | ⏳ |
| 5 | Skill/Worker 5 分钟自动同步 | 在 Nacos 放 Skill → 等同步 → 市场出现草稿 | ✅(POC) |
| 6 | OIDC 对接企业 IdP(飞书/Keycloak) | 配置 OidcConfig → authorize 302 → callback 绑 Developer | ⏳ |
| 7 | 凭证中介 + 数据面消费闭环 | Consumer 凭证 → 网关 → 真实 MCP → 计量 | ⏳ |
七、与 00 总纲的关系说明
本篇替代早期计划中的“供给链/订阅/网关”拆分篇,作为接线专篇横切 01/03/04/05。实证结果回填 00 篇台账与 04 篇;生产架构、凭证中介与验收门槛以 05 篇为准。