166 lines
6.7 KiB
Markdown
166 lines
6.7 KiB
Markdown
# 由壹点通知中心接入指南
|
||
|
||
本文面向需要接入“由壹点”统一钉钉单聊通知的业务项目。业务项目只调用通知中心,不直接持有钉钉应用密钥,也不直接调用钉钉机器人接口。
|
||
|
||
## 1. 接入边界
|
||
|
||
- 通知中心负责:统一机器人身份、项目隔离、签名认证、幂等防重、异步投递、有限重试、已读状态查询,以及在启用免登时按既有 HTTPS 规则包装可用的跳转地址。
|
||
- 业务项目负责:确定通知触发时机、提供准确的钉钉 `userId` 或准确花名、生成稳定的幂等键、提交业务内容、保存通知中心返回的投递 ID。
|
||
- 钉钉 `AppKey`、`AppSecret`、`RobotCode` 只能保存在通知中心。
|
||
- 业务项目只能保存自己独有的项目 HMAC 密钥;禁止把密钥提交到 Git、发送到前端或写入浏览器环境变量。
|
||
|
||
## 2. 接入前只需提供项目名称
|
||
|
||
业务项目只需告诉通知中心一个用户能看懂的项目名称,例如“固定资产”。项目代码和项目密钥由通知中心自动生成;不需要提前提交负责人、使用场景、通知量、跳转域名、收件人方式或花名清单。
|
||
|
||
通知中心完成创建后,通过安全渠道提供:
|
||
|
||
- `YYD_NOTIFICATION_PROJECT_CODE`
|
||
- `YYD_NOTIFICATION_PROJECT_SECRET`
|
||
- `YYD_NOTIFICATION_CENTER_URL`
|
||
|
||
## 3. 业务项目环境变量
|
||
|
||
```dotenv
|
||
YYD_NOTIFICATION_CENTER_URL=https://sc.jiansun.vip/notification-center
|
||
YYD_NOTIFICATION_PROJECT_CODE=fixed_asset
|
||
YYD_NOTIFICATION_PROJECT_SECRET=由通知中心单独分配的项目密钥
|
||
```
|
||
|
||
这些变量只允许出现在业务后端的生产环境中。前端代码不得直接调用通知中心。
|
||
|
||
## 4. 发送接口
|
||
|
||
接口:`POST /v1/notifications`
|
||
|
||
```json
|
||
{
|
||
"idempotencyKey": "disposal_applied:53:approver-user-id:v1",
|
||
"recipientUserId": "钉钉userId",
|
||
"title": "资产报废待审批",
|
||
"content": "**申请时间:** 2026年7月16日 14:30\n\n**资产:** 摄影灯 A-102\n\n**申请人:** 张三",
|
||
"actionTitle": "立即审批",
|
||
"actionUrl": "https://asset.jiansun.vip/workflows/disposals/53"
|
||
}
|
||
```
|
||
|
||
只能提供花名时,将 `recipientUserId` 替换为准确 `recipientAlias`:
|
||
|
||
```json
|
||
{
|
||
"idempotencyKey": "disposal_applied:53:海棠:v1",
|
||
"recipientAlias": "海棠",
|
||
"title": "资产报废待审批",
|
||
"content": "**申请时间:** 2026年7月16日 14:30\n\n**资产:** 摄影灯 A-102",
|
||
"actionTitle": "立即审批",
|
||
"actionUrl": "https://asset.jiansun.vip/workflows/disposals/53"
|
||
}
|
||
```
|
||
|
||
字段约束:
|
||
|
||
| 字段 | 规则 |
|
||
| --- | --- |
|
||
| `idempotencyKey` | 必填,最长 160 字符;同一业务事件、同一收件人必须稳定不变 |
|
||
| `recipientUserId` | 与 `recipientAlias` 二选一;企业通讯录中的钉钉 `userId` |
|
||
| `recipientAlias` | 与 `recipientUserId` 二选一;通知中心会调用素材平台内部目录精确解析,最长 50 字符 |
|
||
| `title` | 必填,最长 100 字符;只写业务主题,不要添加 `【项目名】`,拼接项目名后的最终标题不能超过 120 字符 |
|
||
| `content` | 必填,Markdown 或纯文本都可以;正文最长 4800 字符,通知中心不会再自动插入标题或固定说明 |
|
||
| `actionTitle` | 可选,最长 20 字符;有 `actionUrl` 但未传时默认“查看详情” |
|
||
| `actionUrl` | 可选;非空时按业务项目提交值使用,通知中心不限制协议、公网/内网地址或项目域名白名单 |
|
||
|
||
通知中心会自动生成最终标题:
|
||
|
||
```text
|
||
【{项目名称}】{业务标题}
|
||
```
|
||
|
||
例如业务项目提交“资产报废待审批”,用户最终看到的是:
|
||
|
||
```text
|
||
【固定资产】资产报废待审批
|
||
```
|
||
|
||
通知中心不会再改写正文首行。业务项目提交什么正文,钉钉卡片就发送什么正文。
|
||
|
||
## 5. 请求签名
|
||
|
||
每次请求必须携带:
|
||
|
||
- `x-yyd-project-code`
|
||
- `x-yyd-timestamp`:Unix 秒
|
||
- `x-yyd-nonce`:16~100 位,每次请求重新生成
|
||
- `x-yyd-signature`:HMAC-SHA256 十六进制字符串
|
||
|
||
签名原文:
|
||
|
||
```text
|
||
timestamp\nnonce\nHTTP_METHOD\nPATH\nSHA256(rawBody)
|
||
```
|
||
|
||
注意:
|
||
|
||
- `PATH` 是通知中心内部接口路径,如 `/v1/notifications`,不包含公网反向代理前缀 `/notification-center`,也不包含域名和查询参数。
|
||
- 计算签名的 `rawBody` 必须与实际发送的请求正文逐字节一致。
|
||
- 服务器时间与通知中心相差不能超过五分钟。
|
||
- nonce 不能复用,即使上一次请求失败也要生成新的 nonce。
|
||
|
||
可直接复用的实现见 [`examples/node/notification-client.mjs`](../examples/node/notification-client.mjs)。
|
||
|
||
## 6. 幂等和多人通知
|
||
|
||
当前接口一次只接收一名收件人。向多人发送时,业务项目应逐人创建通知,每个人使用独立但稳定的幂等键。花名方式把下面的 `recipientUserId` 替换成准确花名:
|
||
|
||
```text
|
||
{事件类型}:{业务记录ID}:{recipientUserId}:{消息版本}
|
||
```
|
||
|
||
例如:
|
||
|
||
```text
|
||
survey_created:73a3f3e9:15891598262598724:v1
|
||
survey_created:73a3f3e9:16408293139985728:v1
|
||
```
|
||
|
||
相同 `projectCode + idempotencyKey`:
|
||
|
||
- 请求内容相同:返回原投递记录,不重复发送。
|
||
- 请求内容不同:返回 `409 IDEMPOTENCY_CONFLICT`,业务项目必须修正幂等键设计,不能通过随机换键绕过。
|
||
|
||
## 7. 接收返回值和查询状态
|
||
|
||
创建成功返回 HTTP `202`,表示通知中心已接受任务,不代表钉钉已经送达。业务项目应保存返回的 `id`,必要时调用:
|
||
|
||
```text
|
||
GET /v1/notifications/{id}
|
||
```
|
||
|
||
查询请求也必须签名,GET 请求正文为空字符串。状态含义和处理方式见 [错误与状态规范](./错误与状态规范.md)。
|
||
|
||
## 8. 钉钉 H5 免登是可选能力
|
||
|
||
普通通知接入不需要实现免登。只有用户点击卡片后必须自动进入业务登录态时,才申请开启项目 `login` 配置。
|
||
|
||
开启后业务项目还必须:
|
||
|
||
1. 提供精确的 HTTPS 回调地址和允许回跳的站内路径前缀。
|
||
2. 后端接收一次性票据,并通过签名接口兑换钉钉 `userId`。
|
||
3. 在创建本地 Session 前重新核验账号绑定、在职状态和业务权限。
|
||
|
||
通知中心票据只能证明钉钉身份,不能替代业务项目自身的授权判断。
|
||
|
||
## 9. 最小上线验证
|
||
|
||
接入完成后至少验证:
|
||
|
||
1. 本人收到单聊通知。
|
||
2. 另一名真实员工收到单聊通知。
|
||
3. 最终标题包含正确的项目来源。
|
||
4. 标题包含正确的项目来源,正文保持业务项目提交内容。
|
||
5. 使用相同幂等键重复请求不会重复发送。
|
||
6. 无效 `userId` 能得到明确失败状态。
|
||
7. 创建接口返回 `202` 后,最终状态能进入 `sent`、`unread` 或 `read`。
|
||
8. 日志、错误页和前端响应中均没有项目密钥。
|
||
|
||
完整清单见 [新项目接入清单](./新项目接入清单.md)。
|