Skip to content

12 — 平台表 GraphQL 查询(HMAC) ​

第三方通过 HMAC 调用门户,对管理端已纳入 catalog 且审核授予的平台物理表执行只读 GraphQL 单表查询。

须先申请、后调用:未经审核通过的 Client 无 grant,GraphQL Schema 中看不到对应表。
设计方案:doc/51-通用单表GraphQL查询.md。
与 JDBC 视图区别:09-数据服务-JDBC视图-HMAC.md 查第三方库映射 JSON;本文查平台库白名单表。

查询基路径:/api/open/tables
查询方法:POST /graphql


1. 接入流程 ​

text
1. 打开公开申请页 https://{portal}/open/data-query-apply
2. POST /api/portal/data-query/applications(选表、填用途与联系方式)
3. 等待管理端审核 → APPROVED(绑定 CONFIDENTIAL Client,写入 grant)
4. 使用 bound_client_id + client_secret 调 POST /api/open/tables/graphql
阶段路径鉴权
可选表清单GET /api/portal/data-query/catalog/open无(仅 apply_open=1)
提交申请POST /api/portal/data-query/applications无
进度查询GET /api/portal/data-query/applications?applyCode=无(持 applyCode)
GraphQL 查询POST /api/open/tables/graphqlHMAC

公开申请页路由:/open/data-query-apply(前端独立页,非 /api)。


2. 申请 API(门户公开) ​

2.1 可选表 — GET /api/portal/data-query/catalog/open ​

响应 data 为数组:tableName、tableLabel(仅 catalog apply_open=1 且 enabled=1)。

2.2 提交 — POST /api/portal/data-query/applications ​

字段必填说明
orgName是单位名称
contactName是联系人
contactPhone是电话
contactEmail否邮箱
purpose是用途说明
requestClientId否期望复用的 client_id(须已存在且 CONFIDENTIAL)
tableNames是字符串数组;须在 open catalog 内

成功 data:applyCode、status=PENDING。

2.3 进度 — GET /api/portal/data-query/applications?applyCode= ​

字段说明
applyCode申请单号
statusPENDING / APPROVED / REJECTED / REVOKED
reviewComment审核意见(驳回/通过)
boundClientId通过后绑定的 Client(方可调 GraphQL)
tableNames申请明细

3. GraphQL 查询 — POST /api/open/tables/graphql ​

3.1 鉴权头 ​

与 02-事项推送-HMAC.md、09-数据服务-JDBC视图-HMAC.md 完全一致:

Header必填说明
X-Client-Id是审核通过绑定的 client_id
X-Timestamp是Unix 秒
X-Signature是HMAC-SHA256 Hex

签名串:

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

时间窗:±300 秒。

Client 要求:

  • client_type=CONFIDENTIAL 且启用
  • 已绑定 system_code
  • 审核通过后存在 sys_data_query_grant:principal_type=HMAC_CLIENT、principal_code={clientId}、enabled=1

未开通 grant_type=client_credentials。

3.2 请求 Body ​

字段必填说明
query是GraphQL 查询字符串
variables否变量 JSON
operationName否多操作时指定

3.3 响应(ApiResult 例外) ​

本接口 不 使用门户统一 ApiResult 包装,直接返回 GraphQL 规范 JSON:

json
{
  "data": {
    "sysUser": {
      "total": 100,
      "pageNum": 1,
      "pageSize": 20,
      "records": [
        { "username": "zhangsan", "realName": "张三", "deptCode": "D001", "deptName": "研发部" }
      ]
    }
  },
  "errors": null
}
场景HTTPbody
成功200{ "data": {...}, "errors": null }
部分字段失败200data + errors[](含 path、message)
鉴权失败200 或 401errors[].extensions.code=UNAUTHENTICATED
无 grant / 表不可见200errors 提示未知字段或 FORBIDDEN
签名错误200code 非 0 的 ApiResult(Filter 层拒绝,未进 GraphQL)

注意:仅 GraphQL 执行成功进入引擎 的响应为 {data,errors};HMAC Filter 拒绝(Client 无效、签名错、非 CONFIDENTIAL)仍为 ApiResult 包装,与 02/09 一致。

3.4 示例 ​

bash
BODY='{"query":"query { sysUser(pageNum:1, pageSize:10) { total records { username realName } } }"}'
TS=$(date +%s)
SIG=$(printf '%s\n%s\n%s' "$CLIENT_ID" "$TS" "$BODY" | openssl dgst -sha256 -hmac "$CLIENT_SECRET" | awk '{print $2}')

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

4. Schema 与授权 ​

  • GraphQL Schema 动态生成:仅包含该 Client 有 grant 且 catalog enabled=1 的表。
  • 未授权表:不出现在 Schema(查询未知字段报错,而非返回空列表)。
  • 列:受 doc/42 字段元数据约束(开放面使用 Client 绑定 system_code 下配置的默认字段权限或专用开放角色)。
  • 行:受 doc/45/doc/46 与 catalog 锚点列约束。

5. 错误码摘要 ​

场景典型
Client 非 CONFIDENTIALFilter:code=403,message 说明 Client 类型
无 grantGraphQL FORBIDDEN
表未在 catalog未知字段
分页超限pageSize > 200 → BAD_USER_INPUT
申请未通过调 GraphQL无 grant,Schema 无表

6. 与 MCP 的边界 ​

能力路径鉴权
Agent 按登录用户查平台表POST /api/open/mcp/graphql工具令牌 + mcp:data:query(11-MCP.md)
第三方系统级批查POST /api/open/tables/graphql本文 HMAC
第三方库视图 JSONPOST /api/open/data/queryHMAC(09)

7. 非目标 ​

  • 申请前调用 GraphQL
  • PUBLIC Client、client_credentials
  • Mutation / 任意 SQL
  • 未审核表「先试再申请」