多应用、用户与事件接入
本文说明同一家开发者企业有多个应用时,怎样配置登录、关联客户和处理事件。应用 A、应用 B 是通用示例,不代表真实客户。
1. 需要几个应用
| 产品情况 | 配置方式 |
|---|---|
| 两个独立产品 | 创建两个应用,分别配置登录、API 权限、Webhook 和订阅套餐 |
| 一个产品同时需要用户登录和后台调用 | 在一个应用中启用用户身份和应用身份,无需因此创建两个应用 |
| 同一产品的 Sandbox 与 Production | 使用独立应用;Production 关联已验收的 Sandbox |
开发者后台顶部的企业是应用管理方。一家企业可以管理多个应用;共同归属不会让应用共享 Client、Secret、API 权限、用户授权或付费权益。
两个应用可以使用同一套服务端代码,但请求和事件必须按各自应用、环境及凭据处理。不要用应用 A 的 Client 调用应用 B,也不要合并两个应用的订阅记录。
2. 按用途完成最少配置
只配置产品实际使用的能力。仅接用户登录无需取得应用身份 Secret;不通过平台收费无需先准备订阅套餐。
| 用途 | 开发者提供 | 后台入口 | 联调前确认 |
|---|---|---|---|
| 用户登录 | 应用已实现的登录回调;按需调整自动补全的退出地址与网站来源 | 开发接入 → OAuth/OIDC 配置 → 用户身份 | 身份已启用,当前 Client ID 与精确回调一致;无需 Client Secret |
| 后台 API | 所需 API 与权限 | 凭证与基础信息;开发接入 → API 与权限 → 应用身份 | 身份已启用,API 权限已启用且绑定成功,Secret 保存在服务端 |
| 订阅与支付 | 套餐、平台管理的购买入口、所需接入能力 | 商业管理 → 订阅套餐/收费与履约 | 套餐可售、能力已生效,客户购买页面能读取当前应用和环境的目录 |
| 业务事件 | 事件类型;长连接使用应用身份,HTTPS 接收才需公网地址 | 开发接入 → 事件与 Webhook | 订阅已启用,实际处理后 ACK 或安全接收后返回 2xx |
| 应用目录导流 | 公共 HTTPS 首页或登录页 | 应用管理 → 应用发布信息 | 发布信息已生效;发布不授予客户产品访问权 |
登录回调接收授权码,客户访问地址打开产品,两者用途不同。网站来源只有协议、主机和端口,没有回调路径。
例如,回调为 https://app.example.test/auth/callback 时,网站来源为 https://app.example.test;退出后可返回 https://app.example.test/。应用必须实际实现回调,平台不会替第三方创建路由。
Issuer、Client ID 和已绑定权限从当前应用页面取得,不从另一应用或其他环境复制。详见认证与授权和接收 Webhook。
3. 登录后取得用户与客户空间
完成 OIDC 登录后,应用服务端调用用户与客户空间,首次请求发送 {}。平台自动准备或复用个人空间,并返回当前用户、空间和成员信息;开发者不用手工开户或填写内部映射。
| 标识 | 怎样使用 |
|---|---|
user.open_id | 关联当前应用的用户 |
user.union_id | 同开发者、同环境两个应用关联同一用户 |
space.organization_id | 当前客户空间,后续请求与商业订阅使用该范围 |
space.membership_id | 关联当前用户在这个空间的成员事件 |
application_id、environment | 区分所属应用和 Sandbox/Production |
订阅 id | 关联一份订阅;按事件 Schema 对应 resource_id |
跨应用标识规则见 open_id 与 union_id。Client、授权与付费权益仍各自独立。
客户空间使用不透明的 organization_id;用户无需输入或理解它。开发者企业管理应用,客户空间购买和使用产品,不能把开发者企业 ID 固定用于所有客户请求。OIDC iss + sub、内部身份引用、成员标识与公开用户别名不互换,也不按邮箱合并用户。
空间暂不可用时保留已经验证的登录,显示重新读取入口。应用或成员关系失效时停止该范围操作,要求用户确认选择;不能把原购买静默转入另一个空间。登录与用户关联不会授予产品、商业、额度或平台权限。
4. 事件怎样关联业务记录
先按所选传输方式验证事件来源,按 Schema 核对应用、环境和客户范围。长连接持久处理后 ACK;HTTPS 持久接收后返回 2xx,后台按资源版本处理。以下规则适用于订阅事件,其他事件按各自 Schema 处理。
tenant_id与data.organization_id对应同一个购买方客户工作区。data.open_platform_application_id与接收端当前应用一致,data.environment与当前应用环境一致。- 以应用、环境、客户工作区和订阅
data.id关联记录。不能仅按organization_id合并不同应用的订阅。 - 按
event_id去重,按resource_version更新同一订阅;重复或乱序事件不重复开通、不覆盖新状态。 - 商业订阅与具体成员访问分别核验,企业购买不表示每个成员都可使用。
同一工作区可以分别购买应用 A 和应用 B,两份订阅独立处理。同一个用户通过两个工作区购买同一应用时,两份工作区记录也不能合并。oem.access_context.changed.v1 的成员 subject 用 data.subject_id 关联 space.membership_id,不关联最后登录人。完整字段见事件目录。
5. 最小联调清单
| 场景 | 预期结果 |
|---|---|
| 当前应用用户登录 | 精确回调完成,应用建立自己的会话;不要求应用身份 Secret |
| 首个已授权 API 请求 | 成功;未配置相应 API 权限时明确拒绝 |
| 同一客户分别订阅两个应用 | 回调只更新所属应用的订阅 |
| 一个用户参与两个工作区 | 请求、事件和权益按实际工作区隔离 |
| 错应用、环境或签名 | 拒绝,不修改记录 |
| 重复或旧版本事件 | 去重或忽略旧状态,不重复开通 |
| 新用户无工作区 | 自动准备个人空间,并发与重登复用;暂不可用时保留登录并可恢复 |
| 同开发者两个应用 | 同一用户 union_id 相同,open_id 不同,权限与订阅独立 |
| 失效成员或显式错空间 | 拒绝该范围操作,不静默切换 |
列表中的“需要处理”可能指 Sandbox 验收未完成,不代表已启用的登录一定不可用。进入应用查看具体下一步;配置后先联调所选能力,再按应用接入流程提交验收。
POST /open-platform/v1/user-context:resolve 的请求、响应与故障处理见用户与客户空间。
6. 上报客户端诊断
POST /open-platform/v1/client-diagnostics 使用当前应用用户的 OAuth Bearer 和独立 Idempotency-Key。只上报 request_id、operation、reason_code、status_code 和 duration_ms,不发送请求或响应正文、凭据、用户资料或 URL。应用范围由已验证的登录确定,不接受调用者指定其他应用。
记录标为客户端上报,不能代替服务端调用结果。每用户每应用最多 60 条/分钟,保留七天;成功创建返回 201,相同键和相同内容重放返回 200,不同内容复用键返回 409。认证或当前测试资格不足时返回 401/403,限流返回 429,依赖不可用返回 503。结果未知时保留原键及原内容重试,在开发者后台“客户端日志”按 Request ID 查询并可关联技术反馈。
7. 长连接接收事件
应用后台可配置 HTTPS 推送或长连接。长连接使用当前应用服务 OAuth 配置签发的 Bearer,需 openplatform.api.invoke,不可使用用户登录凭据或将 Token 放入 URL。
通过 GET /open-platform/v1/applications/{id}/events:stream 建立 SSE。收到 delivery 后先持久处理并按 event_id 去重,再调用 POST /open-platform/v1/applications/{id}/events:ack,仅提交该帧的 delivery_id、lease_receipt。同一订阅只有一条未确认投递,租约 30 秒;连接断开或过期可能重复投递。旧租约或重复 ACK 返回 409。遇到错误帧或断线,核对当前应用授权后重新连接;Last-Event-ID 不代表已确认。切换接收方式不会把同步回调转换成异步事件。可直接运行长连接 Node.js 示例。
8. 处理已收到的履约和成员事件
应用身份默认的 openplatform.api.invoke 可以调用下面三项内置接口,无需再申请治理权限、内部回查权限或客户授权。每次请求都验证当前应用身份。能力评估与成员快照仍受当前正式版本、能力和撤权约束;停用应用或机器身份后,原 Token 与原幂等键同样不能继续操作。
| 接口 | 用途 |
|---|---|
POST /open-platform/v1/applications/{id}/integration-features:evaluate | 检查当前应用的接入能力;正文的 application_id、environment 必须与当前应用一致 |
POST /open-platform/v1/applications/{id}/events/{event_id}/access-snapshot | 收到 oem.access_context.changed.v1 后发送 {},取得原事件成员的当前最小权益快照 |
POST /open-platform/v1/applications/{id}/events/{event_id}/fulfillment-result | 处理 oem.fulfillment.requested.v1 后,以稳定 Idempotency-Key 回传原 attempt 与处理结果 |
{event_id} 必须是平台实际为该应用持久记录的事件编号。客户、成员、产品、订阅和履约操作从原事件派生;不接受通过正文、查询参数或组织/应用范围 Header 改选客户。成员快照不包含内部身份、用户资料、委派或其他成员。跨应用事件返回拒绝或不存在,不按 union_id 扩大范围。
履约正文使用 attempt、status(succeeded 或 failed)、retryable,按需提供 product_tenant_id、provider_request_id、error_code、error_message。平台负责调用商业 Owner 并检查原尝试和状态,第三方不保存平台内部 CRM Token。409 表示原尝试已过期或幂等冲突,应重新核对原事件;依赖暂不可用返回 503,使用原请求和原键重试。
版本正常下线或接收端暂停后,已经投递的原履约请求仍可通过结果入口收尾。该入口只接受原事件中的客户、应用、环境、操作和 attempt,并继续检查当前机器身份及商业 Owner 的当前操作状态;不能借此发起新履约、扩大事件范围或读取成员快照。未投递的事件、跨应用事件和过期尝试会被拒绝。