Skip to content

对外集成

对外集成模块面向集团既有平台与第三方系统对接。它提供两块能力:一是 OAuth2 开放接口,第三方系统用 client_credentials 换取访问令牌后,按项目编码拉取项目快照;二是出站 Webhook,把智建云侧发生的关键业务事件(里程碑变更、重大隐患、质量 NCR、采购延误)实时推送到第三方回调地址。

本章读者

本章面向对接方的开发人员,包含接口地址、请求示例与验签代码。管理端的「新建客户端 / 新建 Webhook」等配置操作由项目侧具备集成权限的管理员完成,也可参照本章的操作步骤部分。

功能概述

  • OAuth2 开放接口(client_credentials 模式):管理端创建开放客户端,签发 client_idclient_secret;第三方凭此换取访问令牌,令牌有效期 2 小时。
  • 项目快照拉取:持令牌调用快照接口,一次取回某项目的状态、健康分、计划/实际形象进度、里程碑与未闭环 NCR 等汇总指标。
  • 出站 Webhook 订阅:管理端配置回调地址与订阅事件,业务事件发生时由平台主动 POST 推送。
  • 推送带 HMAC-SHA256 签名(请求头 X-UanBuild-Signature),接收方用配置的密钥验签,确认来源与完整性。
  • 投递失败自动重试(最多 5 次),管理端可查看投递记录、随时发送测试事件联调。

谁能进入本模块

左侧导航「系统集成 → 对外集成」对拥有 integration.view 权限的成员可见。新建、编辑客户端与 Webhook、发送测试事件需要 integration.manage 权限;仅有 integration.view 的成员只能查看列表与投递记录。

界面构成

进入「对外集成」后,页面顶部为两个标签页。

  1. Webhook 回调:Webhook 订阅列表(名称、回调地址、订阅事件、状态),右上角「新建 Webhook」按钮,每行提供「测试」与「投递记录」操作。
  2. 开放接口客户端:OAuth2 客户端列表(名称、client_id、状态、创建时间),右上角「新建客户端」按钮,页脚附换取令牌的接口提示。

一、OAuth2 授权与项目快照

面向需要主动从智建云拉取数据的第三方系统。

步骤 1:创建开放客户端

  1. 进入「开放接口客户端」标签页,点击「新建客户端」。
  2. 填写「名称」(例如:集团数据平台),点击「创建」。
  3. 系统弹出 client_idclient_secret。请立即复制保存。

client_secret 只显示这一次

client_secret 仅在创建时明文返回一次,服务端只保存其哈希值,之后无法再次查看。若遗失只能作废该客户端重新创建。请妥善保管,勿写入前端代码或提交到代码仓库。

步骤 2:换取访问令牌

client_idclient_secret 调用令牌接口。租户码通过请求头 X-Tenant-Code 指定,用于定位你所属的租户。

  • 接口:POST /open/v1/oauth/token
  • 请求头:X-Tenant-Code: <租户码>Content-Type: application/json
  • 请求体:grant_type(可选,若填写必须为 client_credentials)、client_idclient_secret
bash
curl -X POST https://<智建云域>/open/v1/oauth/token \
  -H "X-Tenant-Code: <租户码>" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "ub_xxxxxxxxxxxxxxxxxxxx",
    "client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }'

成功响应(平台统一包装为 { code, message, data }code=0 为成功):

json
{
  "code": 0,
  "message": "ok",
  "data": {
    "access_token": "eyJhbGciOi...",
    "token_type": "Bearer",
    "expires_in": 7200
  }
}

令牌响应字段:

字段说明
access_token访问令牌,用于后续接口的 Authorization: Bearer
token_type固定为 Bearer
expires_in有效期(秒),固定 7200,即 2 小时

令牌已自带租户信息

X-Tenant-Code 只在换取令牌时需要。令牌本身已绑定该租户,后续调用快照等接口时只需带 Authorization: Bearer,无需再传租户码。令牌过期后重新调用本接口换取即可,建议接入方缓存令牌并在临近过期前刷新。

步骤 3:拉取项目快照

持令牌按项目编码拉取该项目的汇总快照。

  • 接口:GET /open/v1/project/{项目编码}/snapshot
  • 请求头:Authorization: Bearer <access_token>
bash
curl https://<智建云域>/open/v1/project/<项目编>/snapshot \
  -H "Authorization: Bearer <access_token>"

成功响应 data 示例:

json
{
  "project_code": "PRJ-2026-001",
  "project_name": "某炼化一体化项目",
  "status": 1,
  "health_score": 82,
  "plan_progress": 63.5,
  "actual_progress": 58.2,
  "milestones_total": 24,
  "milestones_at_risk": 3,
  "open_ncr": 5,
  "generated_at": "2026-07-11T09:30:00+08:00"
}

项目快照字段:

字段类型说明
project_code字符串项目编码
project_name字符串项目名称
status整数项目状态码
health_score整数/空项目健康分(0–100),未评估时为空
plan_progress小数/空计划形象进度(百分比),按叶子 WBS 等权均值计算,无数据时为空
actual_progress小数/空实际形象进度(百分比),口径同上
milestones_total整数里程碑总数
milestones_at_risk整数处于预警或滞后状态(状态码 4、5)的里程碑数
open_ncr整数未闭环的 NCR 数量
generated_at字符串快照生成时间(ISO 8601,东八区,格式 +08:00

二、出站 Webhook

面向需要被动接收智建云事件推送的第三方系统。

步骤 1:创建 Webhook 订阅

  1. 进入「Webhook 回调」标签页,点击「新建 Webhook」。
  2. 填写以下字段:
    • 名称:便于识别的订阅名称。
    • 回调地址:接收推送的 URL,必须以 http://https:// 开头(生产环境建议 HTTPS)。
    • 签名密钥:由你自定义的一段字符串,平台用它对推送体做 HMAC-SHA256 签名,你用同一密钥验签。请妥善保管,勿泄露。
    • 订阅事件:可选「全部事件」或某一具体事件类型。
  3. 点击「创建」。此后订阅的事件发生时,平台会向该地址 POST 推送。

回调地址应尽快返回 2xx

接收端收到推送后应尽快返回 HTTP 2xx 状态码表示接收成功。单次投递的超时为 10 秒,超时或返回非 2xx 都会被判为失败并进入重试。请勿在响应链路里做耗时的同步处理,建议先落库/入队再异步处理。

事件目录

事件类型触发场景界面订阅项
milestone.changed里程碑状态发生变更里程碑变更
hazard.major产生重大隐患
ncr.created生成质量不符合项(NCR)NCR 产生
procurement.delay关键路径物资延误拖累里程碑关键路径物资延误

订阅「全部事件」时接收上述所有事件;订阅具体某一类时只接收该类。接收端应始终以推送体内的 event 字段判断事件类型,并对未识别的类型做兼容处理。

事件推送格式

每次推送为一个 POST 请求,请求头包含:

请求头说明
Content-Typeapplication/json
X-UanBuild-Event事件类型(与推送体内 event 字段一致)
X-UanBuild-Signature签名,格式 sha256=<十六进制小写>,见「验证签名」
User-Agentuanbuild-backend/<版本号>

推送体是一个 JSON 对象,始终包含标识事件类型的 event 字段,外加该事件的业务字段(含 project_id)。以下为两个代表性事件的字段说明。

ncr.created(质量 NCR 生成)示例与字段:

json
{
  "event": "ncr.created",
  "project_id": 12,
  "ncr_id": 305,
  "code": "NCR-2026-0012",
  "title": "焊缝外观不合格",
  "level": 2
}
字段说明
event固定 ncr.created
project_id所属项目 ID
ncr_idNCR 记录 ID
codeNCR 编号
title问题标题
level问题级别(数值,越大越严重)

procurement.delay(关键路径物资延误)示例与字段:

json
{
  "event": "procurement.delay",
  "project_id": 12,
  "milestone_id": 88,
  "status": 5,
  "status_text": "滞后",
  "caused_by_order": 47
}
字段说明
event固定 procurement.delay
project_id所属项目 ID
milestone_id受影响的里程碑 ID
status里程碑新状态码(4=预警,5=滞后)
status_text状态文字(预警 / 滞后)
caused_by_order造成延误的采购单 ID

字段以推送体为准

不同事件的业务字段不同。接入方应按 event 字段分支解析,并对字段做防御式读取(缺省字段容错),以适应后续事件字段的扩展。milestone.changedhazard.major 的推送体同样遵循上述封装:始终含 eventproject_id,并携带对应业务对象的标识与关键信息。

验证签名

平台用该 Webhook 配置的「签名密钥」对推送的原始请求体计算 HMAC-SHA256,结果转为十六进制小写,放入请求头 X-UanBuild-Signature,格式为 sha256=<hex>

接收端应对收到的原始请求体(未经反序列化改动的字节)用同一密钥重算,并与请求头比对。验签通过才处理事件。

验签伪代码:

text
signature_header = 请求头 X-UanBuild-Signature          # 形如 "sha256=abcd..."
expected = "sha256=" + hex_lower(HMAC_SHA256(密钥, 原始请求体))
if constant_time_equal(signature_header, expected):
    接受并处理事件
else:
    拒绝(返回 4xx),记录可疑推送

Python 示例:

python
import hashlib, hmac

def verify(secret: str, raw_body: bytes, signature_header: str) -> bool:
    digest = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    expected = "sha256=" + digest
    return hmac.compare_digest(expected, signature_header)

Node.js 示例:

js
const crypto = require('crypto')

function verify(secret, rawBody, signatureHeader) {
  const digest = crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
  const expected = 'sha256=' + digest
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signatureHeader))
}

用原始请求体验签,并用恒定时间比较

必须对未经解析、未重新序列化的原始请求体字节计算签名。若先把 JSON 反序列化再序列化回字符串,字段顺序或空白差异会导致签名不匹配。比较签名时使用恒定时间比较函数(如上例的 compare_digest / timingSafeEqual),避免时序侧信道。

投递、重试与失败处理

  • 每条事件对每个订阅它的启用中 Webhook 生成一条投递记录并入队推送。
  • 返回 HTTP 2xx 视为投递成功;非 2xx 响应、连接失败或 10 秒超时均记为一次失败。
  • 失败自动重试,单条投递累计尝试上限为 5 次;达到上限仍未成功则标记为「失败」,不再重试。
  • 若某 Webhook 在重试期间被禁用或删除,其待投递记录会直接标记失败,不再推送。

接收端应做幂等处理

由于存在重试,同一事件可能被投递多次。请以事件内的业务标识(如 ncr_idmilestone_id)做去重,保证重复接收同一事件不会造成重复业务处理。

查看投递记录与发送测试事件

  1. 在「Webhook 回调」列表中,点击目标 Webhook 行的「投递记录」,查看最近 50 条投递(事件类型、状态、尝试次数、响应码、时间)。
  2. 联调时,点击「测试」向该 Webhook 发送一条测试事件,接收端可据此验证连通性与验签逻辑。测试事件推送体示例:
json
{
  "event": "webhook.test",
  "message": "这是一条测试事件",
  "at": "2026-07-11T09:30:00+08:00"
}

测试事件同样带签名

测试事件与正式事件走同一条投递通道,请求头 X-UanBuild-Eventwebhook.test,并带 X-UanBuild-Signature 签名,可用来完整验证接收端的验签实现。仅启用中的 Webhook 可发送测试。

字段与状态说明

开放客户端列表字段:

字段说明
名称客户端名称
client_id客户端标识(ub_ 前缀)
状态启用 / 停用(停用后无法换取令牌)
创建时间客户端创建时间

Webhook 列表字段:

字段说明
名称订阅名称
回调地址接收推送的 URL
订阅事件all(全部)或具体事件类型
状态启用 / 停用(停用后不再推送,也不能发测试)

投递记录状态:

状态含义
待发已入队,等待投递或等待下一次重试
成功接收端返回 2xx,投递完成
失败达到重试上限仍未成功,或 Webhook 已被禁用/删除

投递记录还包含尝试次数(attempts)、响应码(response_code,接收端返回的 HTTP 状态码)与最近一次错误信息(last_error),用于排查失败原因。

注意事项与常见问题

  • 换令牌报「缺少 X-Tenant-Code 头」:令牌接口必须带 X-Tenant-Code 请求头指定租户码,缺失会返回 400。
  • 换令牌报「client 凭据无效」或「client 已禁用」:核对 client_id/client_secret 是否正确、有无多余空格,以及该客户端是否已被停用。为防枚举,凭据错误与客户端不存在返回一致的提示。
  • 调用快照报令牌无效或过期:令牌有效期 2 小时,过期需重新换取。请确认 Authorization 头格式为 Bearer <token>
  • 快照报「项目不存在」:确认路径中的项目编码属于当前令牌所绑定的租户,且项目未被删除。
  • 验签总是不通过:确认使用的是「未经二次序列化的原始请求体字节」计算签名,且比对的是去掉 sha256= 前缀后的十六进制小写值;密钥须与创建 Webhook 时填写的完全一致。
  • 收到重复推送:属预期行为(重试机制所致),接收端需按业务标识做幂等去重。
  • 测试事件发不出去:仅启用状态的 Webhook 可发送测试事件;若已停用,请先启用。

沅虹科技 · 工程与安全生产智能管控平台