Skip to content

14 — 菜单同步(HMAC)

第三方将业务系统菜单 / 权限树节点写入门户 sys_permission,供角色授权与门户导航使用。

方向:你 → 门户(入向)。
代码锚点OpenMenuControllerOpenMenuHmacFilterOpenMenuInboundServicePermissionMenuService.upsertFromOpenApi

基路径/api/open/menus
方法:全部为 POST(含删除语义的 /delete)。

管理端菜单 CRUD(/api/system/menus)需门户登录 + system:menu:*不是第三方入站面。


1. 鉴权头

Header必填说明
X-Client-IdSSO client_id
X-TimestampUnix (epoch seconds)
X-SignatureHMAC-SHA256 的 Hex(大小写不敏感比对)
X-Idempotency-Key可选;记入 sync_menu_push_log,管理端「消息日志 · 菜单」可查;业务幂等键为 system_code + menuCode

时间窗:±300 秒。超出返回 code=401「X-Timestamp 超出允许时间窗」。

Client 须:存在、启用、绑定 system_code、CONFIDENTIAL 且可解析 client_secret。否则 401/403

system_code 始终取自 Client 绑定,请求体无法覆盖。


2. 签名算法

签名串(三个部分用 换行符 \n 拼接,含请求体原文):

text
{clientId}\n{timestamp}\n{rawBody}
规则
算法HmacSHA256,密钥为 client_secret 的 UTF-8 字节
输出Hex 字符串 → 放入 X-Signature
rawBodyHTTP 请求体原始字节按 UTF-8 解码后的字符串;须与实际上送 JSON 字节完全一致

02-事项推送-HMAC.md 算法一致,可复用同一签名工具。


3. 接口清单

方法路径语义
POST/api/open/menus/upsert按绑定 system_code + menuCode 创建或更新;可带 children(先父后子)
POST/api/open/menus/deletemenuCode 软删;仅 create_source=API

成功响应 data

字段说明
permissionId门户 sys_permission.id(删除时可能为空)
menuCode菜单编码
systemCodeClient 绑定系统编码
createSource恒为 API

仅落库成功才 code=0


4. 创建来源隔离(create_source

create_source含义开放接口
API本接口写入可 upsert / delete
PAGE菜单管理页创建禁止改/删 → code=409
PORTAL_APP门户应用连带生成禁止改/删 → code=409

已存在同 menuCode 且来源非 API 时,upsert 返回 409,不会覆盖。


5. UPSERT — POST /api/open/menus/upsert

请求体字段

字段必填说明
menuCode节点唯一编码(字母数字 _ - :
typedirectory / menu / button / link
title显示标题
parentCode父节点 menuCode;根节点省略
permCode条件button 必填;其它可选
path条件directory / menu 必填
component条件menu 必填
link条件link 必填
icon / order / hideInMenu / keepAlive / affixTab / name / redirect / isAuth / extra同管理端菜单字段
children子节点数组;写入时先父后子;子节点未填 parentCode 时自动挂当前节点

示例

bash
BODY='{"menuCode":"hwy_home","type":"link","title":"高速首页","link":"https://highway.example.com/","permCode":"app:highway:view","order":1}'
TS=$(date +%s)
SIG=$(…HMAC Hex…)
curl -sS -X POST "https://portal.example.com/api/open/menus/upsert" \
  -H "Content-Type: application/json" \
  -H "X-Client-Id: demo-client" \
  -H "X-Timestamp: $TS" \
  -H "X-Signature: $SIG" \
  -d "$BODY"

树形示例(目录 + 子链接):

json
{
  "menuCode": "hwy_root",
  "type": "directory",
  "title": "高速系统",
  "path": "/highway",
  "children": [
    {
      "menuCode": "hwy_toll",
      "type": "link",
      "title": "收费查询",
      "link": "https://highway.example.com/toll",
      "permCode": "HWY_TOLL_VIEW"
    }
  ]
}

6. DELETE — POST /api/open/menus/delete

json
{ "menuCode": "hwy_toll" }
错误说明
400存在子菜单,无法删除
404菜单不存在
409API 来源,禁止删除

7. 边界

能力方向文档
菜单同步(本文)你 → 门户HMAC /api/open/menus
组织/用户出向门户 → 你05-组织用户同步.md
权限分配出向门户 → 你14-角色权限分配同步.md(权限分配同步)
角色同步入向你 → 门户16-角色同步-HMAC.md
管理端菜单门户会话/api/system/menus(非开放面)

门户应用连带菜单见内部稿 doc/43;开放写入统一打标 create_source=API