Service Token 与 Webhook
机器身份、签名验签、幂等投递和缓存失效
Service Token 与 Webhook
业务 App 的服务端任务使用 Service Token 调用 IWish Auth;权限或身份上下文发生变化时,IWish Auth 通过 Webhook 通知业务 App 清理缓存。两者都只允许在服务端使用。
1. Service Token
管理员在“系统集成”中先创建 Service Account,再签发 iwa_ 开头的 Token。
- Token 明文只显示一次,必须立即写入业务 App 的服务端 Secret 管理。
- 数据库只保存带服务端 pepper 的 HMAC-SHA256 hash。
- Service Account 可以绑定 App、组织、scope 和到期时间。
- Token scope 必须是 Service Account scope 的子集。
- 停用 Service Account 或吊销 Token 后立即失效,不依赖员工会话。
- 禁止把 Token 写入浏览器、
NEXT_PUBLIC_*、日志、Git 或 Manifest。
服务端权限检查:
import { IWishAuthClient } from "@iwish/auth-sdk";
const auth = new IWishAuthClient({
apiUrl: process.env.IWISH_AUTH_API_URL!,
token: process.env.IWISH_AUTH_SERVICE_TOKEN!
});
const decision = await auth.checkUserPermission({
userId,
organizationId,
appKey: "crm",
permission: "crm.contact.read"
});
Python 使用 check_user_permission(...),字段语义相同。
2. Webhook 请求
创建或轮换 endpoint 时,管理后台只显示一次 whsec_ 开头的签名密钥;接收方必须立即保存到服务端 Secret 管理中。
请求头:
IWish-Event-Id: <uuid>
IWish-Event-Type: permission.changed
IWish-Delivery-Id: <uuid>
IWish-Delivery-Attempt: 1
IWish-Timestamp: <unix-seconds>
IWish-Signature: v1=<hex-hmac-sha256>
签名原文必须使用未解析、未重新序列化的原始请求体:
<timestamp>.<eventId>.<rawBody>
TypeScript 验签:
import { verifyIWishWebhook } from "@iwish/auth-sdk/webhook";
const rawBody = await request.text();
const event = await verifyIWishWebhook({
secret: process.env.IWISH_AUTH_WEBHOOK_SECRET!,
rawBody,
headers: request.headers
});
Python 验签:
from iwish_auth import verify_iwish_webhook
event = verify_iwish_webhook(
secret=webhook_secret,
raw_body=await request.body(),
headers=request.headers,
)
SDK 默认拒绝超过 300 秒的时间戳、签名不匹配、事件 ID 不一致和无效 Envelope。
3. 幂等与缓存失效
接收方必须持久化 IWish-Event-Id,重复事件直接返回 2xx。不要按 Delivery ID 幂等,因为同一个 Event 可能重试多次。
Envelope 的 cacheInvalidation 包含:
userIdsorganizationIdsappKeysclientProjectIds
业务 App 收到 user.disabled、user.role_changed、permission.changed、organization.app_disabled、employee.disabled 或客户项目团队变更时,应清理与上述维度相交的权限和上下文缓存。业务 App 是否消费客户项目数据仍由自身业务决定。
4. 投递策略
投递状态依次使用 pending、processing、delivered、failed 和 dead_letter,便于业务 App 和运维工具统一识别。
- 成功:HTTP 2xx。
- 自动重试:1 分钟、5 分钟、30 分钟、2 小时,最多 5 次。
- HTTP 410:立即进入死信并停用 endpoint。
- 其他失败:耗尽次数后进入死信,可在管理后台人工重试。
- 接收方应在 10 秒内返回;耗时业务先入本地队列再返回 2xx。
5. 安全边界
- 生产 endpoint 只接受公网 HTTPS URL。
- 密钥轮换后旧版本立即失效。
- 不记录 Authorization、Token、签名密钥或完整敏感 payload。
- CORS 使用精确 allowlist;基于 Cookie 的状态变更请求不属于 IWish Auth API 协议。
- 受保护写接口使用 Cloudflare Rate Limiting binding。