本文档由 石墨办公 提供。
Signature 是您的应用接入身份的凭证。它由 appId + appSecret 派生,最常被石墨用来校验"这次请求确实来自您的应用";在石墨主动通知您的应用的场景里,它也是您的应用反向验真的唯一线索。Signature 出现在两条链路上,方向相反、校验侧不同:Signature 不携带业务信息,里面只有"我是谁(kid)+ 什么时候过期(exp)+ 必要时的 scope / fileId"。业务上下文请放进 签名凭证 Token。Signature 是短期凭证。过期时间越长,泄露后的爆炸半径越大;建议默认几分钟到 10 分钟内。注意:部分高敏感接口要求 exp ≤ 5 分钟。appSecret 永远不离开您的应用后端:不进前端、不进 App、不写日志、不进静态配置、不进代码仓库。Signature 是一个标准 JWT,三段式:Header . Payload . Signature
xxxxx . yyyyy . zzzzzkid 必填——它就是您的 appId,石墨用它定位用哪把 appSecret 校验。{
"alg": "HS256",
"typ": "JWT",
"kid": "your_app_id"
}{
"exp": 1612411882,
"scope": "license",
"fileId": "file_123"
}| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
exp | number | 是 | 过期时间,秒级时间戳。校验逻辑:当前秒 < exp 才有效 |
scope | string | 否 | 接口访问范围。调用 license / 系统管理类接口时必须带 "license" |
fileId | string | 否 | 文件标识。仅 /admin 类接口需要,用来把签名作用范围限定到单文件 |
exp 一定要"秒"。是 JWT 标准里默认的单位。kid 必须落在 Header,不要塞到 Payload。exp 校验对偏差敏感,建议所有节点跑 NTP,控制偏差在 ±2 分钟内。appSecret 从配置中心 / KMS 读取,不要硬编码。<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>appId / appSecret 上传到任何服务器。如对安全性要求更高,可拉源码本地跑:Signature 后必须经过如下流程校验:kid → secret 的映射要做。多 App 共用一个回调入口时,先按 kid 找到对应的 appSecret,再算 HMAC,否则没法分辨同一个 endpoint 上不同应用的请求。exp 校验允许小幅容差。建议 ±2 分钟,覆盖正常的 NTP 抖动;超出直接 401。scope 与接口要求要对得上。例如 /admin/* 类接口必须带 scope=license,否则 403。Signature 是一次性消费。即使没过期也不要拿同一个 Signature 反复打多个接口。否规则会导致风险面扩大。在主动通知场景,校验侧是您的应用。详见 签名凭证:Signature 与 Token § 回调接口的鉴权实现。
Signature 出错时返回的状态码通常是 401 / 403,错误信息里常出现 signature / kid / exp。按顺序排查:| 现象 | 检查点 | 修复方向 |
|---|---|---|
错误信息提示 kid invalid 或"应用不存在" | Header 是否包含 kid=AppId | appId 写入 Header 的 kid,不要塞 Payload |
错误信息提示 signature mismatch | HMAC 计算 / Base64URL 编码是否标准 | 用 appSecret 做 HMAC-SHA256,再 Base64URL,拼成 header.payload.signature;不要二次拼接或转义 |
错误信息提示 exp expired | exp 单位 / 服务器时间 | 必须秒级时间戳;所有节点跑 NTP;偏差控制 ±2 分钟 |
| 401 / 403 但本地用 生成工具 可通过 | 环境配置 | 确认线上配置的 appId / appSecret 与请求一致,避免测试 / 生产串包 |
调用 /admin 或 /license 类接口被拒 | 缺 scope / fileId | 这类接口必须显式带 scope=license,部分接口还要带 fileId |
| 主动通知场景的回调验签失败 | 是否按 X-WebOffice-Credential-Type: 3 分支走"仅 Signature"校验 | 同一回调 endpoint 要支持两种入站方式,详见02. 鉴权与安全 |
| 误区 | 实际影响 | 正确做法 |
|---|---|---|
前端持有 appSecret、本地签 Signature | 一旦泄露整个接入身份被人冒用,且不可吊销 | Signature 一律后端签发,前端只拿结果 |
exp 写成毫秒级 | 表面通过校验,但语义上等于"几十年后",部分网关会直接拦截 | 严格秒级 (time.Now().Unix() / int(time.time())) |
exp 设得很长(小时 / 天级) | 一次泄露长时间可用,等于实质上无防护 | 默认几分钟,严格接口 ≤ 5 分钟 |
同一个 Signature 在前端被复用打多个接口 | 一旦窗口过期后续请求全部失败 | 每次会话取一次新的 signature + token |
| 使用其他算法(RS256 / ES256 / none) | 石墨直接 401 | 固定 HS256 |
kid 放进 Payload 而非 Header | 石墨找不到应用 → 401 | kid 必须落在 Header |
appSecret 提交到代码仓库 | 一次泄露永久泄露,且各分支都被污染 | 用 KMS / Vault / 环境变量;CI 跑秘密扫描 |
调用 /license 接口忘了 scope=license | 403 | 严格按接口文档加 scope,并把 exp 缩到 ≤ 4 分钟 |
| 多节点服务器时钟未同步 | 偶发合法请求被判过期 / 重放 | 所有节点跑 NTP;签发 / 校验都允许 ±2 分钟容差 |
把 Signature 当业务幂等键 | Signature 每次都不一样,根本不可比对 | 业务幂等键独立维护(事件 id / 任务 id) |