一句话理解这套系统
服务端签发一张私钥签名的票据,客户端用公钥验签。客户端永远拿不到私钥,所以伪造不了; 票据绑定域名 + 站点实例 ID,复制到别的站立刻失效。
一个服务端可以同时服务多个产品:每个产品一个标识、一套独立密钥对、一批独立授权码,互不干扰。
┌──────────────────┐ HTTPS POST (JSON) ┌────────────────────────┐ │ 插件 A(客户端) │ ────────────────────▶ │ │ │ 插件 B(客户端) │ ────────────────────▶ │ jile-auth-server │ │ 插件 C(客户端) │ ────────────────────▶ │ (唯一一台授权服务器)│ └──────────────────┘ ◀──────────────────── └────────────────────────┘ 签名响应 (payload.sig)
接入三步走
1. 拿到产品的 slug 与公钥
在「产品中心」找到目标产品,记下 slug;公钥可在「我的授权 → 授权详情」页复制,或通过接口实时获取。
GET https://loongpalace.com.cn/?rest_route=/jile-auth/v1/pubkey&product=jile-huiyuan
// → { ok:true, product:"jile-huiyuan", algo:"ed25519", public_key:"...", server_time:1791185585 }
2. 激活(占用站点名额)
POST https://loongpalace.com.cn/?rest_route=/jile-auth/v1/activate
Content-Type: application/json; charset=utf-8
{
"product": "jile-huiyuan",
"key": "JLM-7K2P-QW9M-XZ4T-HB6N",
"domain": "www.myshop.com",
"instance":"a9f2c7d81b4e5f60a1b2c3d4e5f60718",
"plugin_version": "1.10.1",
"nonce": "24randomcharsforantireplay"
}
3. 定时心跳续期
激活后注册定时任务,建议一天两次。心跳失败不会立刻失效,会进入宽限期。
// 激活后注册 if ( ! wp_next_scheduled( XXX_License::CRON_HOOK ) ) { wp_schedule_event( time() + HOUR_IN_SECONDS, 'twicedaily', XXX_License::CRON_HOOK ); }
公共请求参数
| 参数 | 说明 |
|---|---|
product | 产品标识 slug,必须与你在产品中心看到的一致 |
domain | 站点域名(小写、去 www / 协议 / 端口 / 路径) |
instance | 站点实例 ID(32 位随机串,首次生成后永久保存) |
plugin_version | 插件版本,用于版本限定校验 |
wp_version / php_version | 环境信息,便于排错 |
ts | 客户端时间戳 |
nonce | 24 位随机串,防重放;activate 与 voucher/redeem 强制校验 |
接口清单
命名空间 jile-auth/v1,URL 一律使用 ?rest_route= 形式,避开固定链接与 301 降级问题。
| 端点 | 方法 | 用途 | 响应要点 |
|---|---|---|---|
/pubkey | GET | 取产品公钥 | algo、public_key、server_time |
/activate | POST | 激活(占用站点名额) | ticket、expires_at、max_sites |
/heartbeat | POST | 续期票据 | 新的 ticket |
/deactivate | POST | 解绑本站 | 无 ticket |
/voucher/verify | POST | 兑换码校验(不核销) | 签名 payload:码信息 |
/voucher/redeem | POST | 兑换码核销(不可逆) | 签名 payload:核销结果 |
ℹ
全部接口走限流:同 IP 每 60 秒 60 次,超限返回 HTTP 429
rate_limit。错误码
| 错误码 | 含义 | 如何处理 |
|---|---|---|
no_product | 产品标识不存在 | 检查 slug 是否与应用端一致(最常见) |
product_mismatch | 授权码不属于本产品 | 提示用户换对应产品的码 |
domain_mismatch | 站点数已达上限 | 提示先到授权后台解绑 |
not_activated | 该站点未激活此授权码 | 引导用户先激活 |
expired / revoked | 已过期 / 已吊销 | 停用新交易,提示续期或联系客服 |
version_mismatch | 授权码限定了别的版本 | 提示回到指定版本(升级或回退都不行) |
rate_limit | 请求过于频繁 | 稍后重试 |
票据格式
激活与心跳成功后返回 ticket,格式为 payload_b64url.sig_b64url。解码 payload 后包含:
v 票据版本(当前 1) alg 签名算法 ed25519 / rsa jti 票据唯一 ID pid 产品标识,客户端必须校验 lic 授权码指纹 sha256(license_key) 前 16 位 dom 域名指纹 sha256('wpl-lic|' + domain) ins 站点实例 ID iat 签发时间 exp 票据过期时间 = iat + ticket_ttl lexp 授权码到期时间,0 = 永久 grace 宽限天数 site 允许站点数
验签顺序
- 按
.拆成两段,段数必须为 2,否则「票据格式错误」 - base64url 解码 payload 并解析,失败则「票据无法解析」
- 先验签:用公钥验证 sig —— 签名对象是 base64url 编码后的 payload 字符串,不是解码后的 JSON
- 校验
dom与本站域名指纹一致 - 校验
ins与本站实例 ID 一致 - 校验
pid与自身产品标识一致 - 最后判时间:
lexp→exp+grace→ 时间回拨检测
最常踩的坑:第 3 步签名对象写错。必须对 base64url 编码后的 payload 原串验签,写错会 100% 验签失败。
安全约定
| 约定 | 原因 |
|---|---|
| 授权服务器地址写死在代码里 | 若可改,攻击者可指向自建假服务器签出「合法」票据 |
| 公钥验签,私钥永不下发 | 客户端验得了但伪造不了 |
sslverify = true 永不关闭 | 防中间人伪造授权响应 |
| 票据绑定域名 + 实例 ID | 复制到别的站立刻失效 |
| 服务器时间以服务端为准 | 本地调时间无法延长有效期 |
| 核销接口强制 nonce | 防止同一请求重放导致重复核销 |
| 不提供客户端回滚接口 | 否则会被用于「兑换 → 回滚 → 再兑换」无限循环 |