Skip to content

07 — 通知公告推送(HMAC)

第三方将平台广播公告写入门户通知公告域(portal_notice / inbox)。
与事项推送(02分管道:用户侧进 /api/notice/inbox/api/portal/matters

推荐先读08-待办与通知公告-集成手册.md(选型 + 双管道示例)

代码锚点:OpenNoticeControllerOpenNoticeHmacFilterOpenNotice*Request
设计方案:doc/36-第三方推送-通知公告与待办.md

基路径/api/open/notices
方法:全部为 POST


1. 鉴权头

02-事项推送-HMAC.md 完全一致

Header必填说明
X-Client-IdSSO client_id
X-TimestampUnix
X-SignatureHMAC-SHA256 的 Hex
X-Idempotency-Key记入 portal_notice_push_log,便于对账(管理端「消息日志」)

时间窗:±300 秒。Client 须存在、启用、绑定 system_code、CONFIDENTIAL 且可解析 client_secret

签名串:

text
{clientId}\n{timestamp}\n{rawBody}

system_code 始终取自 Client 绑定,不要在 body 里依赖自带 systemCode。

一期安全:TLS + HMAC(无 L3 载荷信封)。签名算法细节与伪代码见 02 §208 §2


2. 接口清单

方法路径语义
POST/api/open/notices/publishsystem_code + externalId 首次发布;已存在 → code=409
POST/api/open/notices/recall按绑定 system_code + externalId 撤回

成功 publishdata

字段说明
noticeId / noticeCode门户公告标识
externalId回显
dispatchModeSYNC / ASYNC(预估受众 >500 异步)
dispatchStatus / estimatedRecipients / taskCode?投递信息

3. PUBLISH — POST /api/open/notices/publish

字段必填说明
externalId对方业务主键;与 Client system_code 幂等
noticeType默认 NOTICE;允许 ALERT / REMIND
title标题
summary摘要
content正文
pcUrl / mobileUrl跳转 URL
initiatorUsername门户登录名;则记 open:{clientId}
audience见下表

audience

字段条件说明
mode必填USERS / DEPTS / ALL
usernamesmode=USERS门户登录名列表(须已存在)
deptCodesmode=DEPTS部门业务编码
includeSubDeptsmode=DEPTS是否含下级,默认 true

同键再次 publish → 409(一期不做内容 upsert)。受众解析结果为空 → 400

请求示例

指定用户

json
{
  "externalId": "ANN-1001",
  "title": "放假通知",
  "summary": "摘要",
  "content": "正文",
  "audience": { "mode": "USERS", "usernames": ["zhangsan"] }
}

按部门

json
{
  "externalId": "ANN-DEPT-1",
  "title": "部门通知",
  "audience": {
    "mode": "DEPTS",
    "deptCodes": ["D001"],
    "includeSubDepts": true
  }
}

全员

json
{
  "externalId": "ANN-ALL-1",
  "title": "全员公告",
  "audience": { "mode": "ALL" }
}

curl

bash
CLIENT_ID="demo-client"
SECRET="your-client-secret"
TS=$(date +%s)
BODY='{"externalId":"ANN-1001","title":"放假通知","audience":{"mode":"USERS","usernames":["zhangsan"]}}'
SIG=$(node -e "const c=require('crypto');const b=process.argv[1],id=process.argv[2],ts=process.argv[3],s=process.argv[4];console.log(c.createHmac('sha256',s).update(id+'\n'+ts+'\n'+b).digest('hex'))" "$BODY" "$CLIENT_ID" "$TS" "$SECRET")

curl -sS -X POST "https://portal.example.com/api/open/notices/publish" \
  -H "Content-Type: application/json" \
  -H "X-Client-Id: $CLIENT_ID" \
  -H "X-Timestamp: $TS" \
  -H "X-Signature: $SIG" \
  -d "$BODY"

成功响应示例

json
{
  "code": 0,
  "message": "success",
  "data": {
    "dispatchMode": "SYNC",
    "noticeId": 1234567890123456789,
    "noticeCode": "ANN-...",
    "externalId": "ANN-1001",
    "dispatchStatus": "SUCCESS",
    "estimatedRecipients": 1,
    "taskCode": null
  },
  "traceId": "a1b2c3d4e5f6"
}

4. RECALL — POST /api/open/notices/recall

字段必填说明
externalId对方业务主键

公告须已存在,否则 404「公告不存在: {systemCode}/{externalId}」。
撤回后个人 inbox 不再展示;进行中的异步投递会尝试取消。

bash
TS=$(date +%s)
BODY='{"externalId":"ANN-1001"}'
SIG=$(node -e "const c=require('crypto');const b=process.argv[1],id=process.argv[2],ts=process.argv[3],s=process.argv[4];console.log(c.createHmac('sha256',s).update(id+'\n'+ts+'\n'+b).digest('hex'))" "$BODY" "$CLIENT_ID" "$TS" "$SECRET")

curl -sS -X POST "https://portal.example.com/api/open/notices/recall" \
  -H "Content-Type: application/json" \
  -H "X-Client-Id: $CLIENT_ID" \
  -H "X-Timestamp: $TS" \
  -H "X-Signature: $SIG" \
  -d "$BODY"

5. 错误与联调提示

现象排查
缺少 HMAC 鉴权头三个头是否齐全、是否被网关剥离
HMAC 签名校验失败body 是否被重新序列化;换行是否为 \n;secret 是否最新
Client 未绑定 system_code管理端补绑
code=409 公告已存在externalId 勿重复 publish;需改内容请另开新 externalId 或先业务侧约定
受众解析结果为空用户名/部门编码是否在门户存在
用户在「事项」里找不到公告只出现在「通知公告」收件箱

6. 与事项推送选型

场景用哪条
审批待办、办理态、重开/api/open/matters
流程抄送/少数人知会/api/open/mattersNOTICE + parties)
全员/按部门广播公告、可撤回本接口 /api/open/notices

同一业务主键不要两条管道各推一条。

公共约定见 01-接入准备.md;双管道速查见 08