鸽子网络验证 · 客户端接入指南
鸽子网络验证提供基于 HTTP 的卡密授权验证服务。客户端通过 AppKey 与
AppSecret 对请求签名,调用接口完成卡密激活、验证与心跳保活。
所有接口同时支持 POST 与 GET:
POST 使用 JSON 请求体;GET 将参数放在 URL query string。
响应体统一为 JSON。推荐使用 POST(参数不出现在 URL,更安全)。
若客户端因代理/防火墙导致 POST 被降级为 GET,服务端也能正常处理,无需特殊配置。
AppKey 与 AppSecret。API 基础地址:https://wlyz.nogay.cn
每个请求必须携带 app_key、device_id、
timestamp(Unix 秒)与 sign 四个字段;
强烈建议同时携带 nonce(随机串)以启用防重放。
签名规则(推荐,带 nonce):
sign = md5(app_key + device_id + timestamp + nonce + app_secret)
兼容旧版(不带 nonce):
sign = md5(app_key + device_id + timestamp + app_secret)
其中 + 表示字符串直接拼接,拼接后取 32 位小写 MD5。
服务器会校验 timestamp 与当前时间的误差(默认 300 秒,可在系统设置中调整),
超出范围将拒绝请求,请确保客户端时间准确。nonce 建议 16 位以上随机串,
同一 nonce 在时间窗内只能使用一次,重复请求会被拒绝(防重放)。
首次使用卡密时调用,将卡密与当前设备绑定,并计算有效期。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| app_key | string | 是 | 应用标识 |
| device_id | string | 是 | 设备唯一标识 |
| timestamp | int | 是 | Unix 时间戳(秒) |
| sign | string | 是 | 签名 |
| code | string | 是 | 卡密 |
成功响应:
{
"code": 0,
"msg": "激活成功",
"data": {
"card_kind": 1,
"expire_at": "2026-11-10 00:55:20",
"bound_count": 1,
"max_devices": 2
}
}
程序运行过程中校验授权是否有效。可传入 code,也可省略(凭已绑定设备识别)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| code | string | 否 | 卡密(省略时按设备查找) |
| 其余公共参数同 activate | |||
成功响应:
{
"code": 0,
"msg": "验证通过",
"data": {
"card_kind": 1,
"expire_at": "2026-11-10 00:55:20",
"remaining": null,
"heartbeat": 300
}
}
定期调用以维持在线状态,建议按响应中的 heartbeat(秒)间隔调用。
{
"code": 0,
"msg": "心跳正常",
"data": { "heartbeat": 300, "server_time": "2026-10-11 00:55:20" }
}
客户端退出时调用,将设备标记为离线。
获取最新公告列表,无需签名。
{
"code": 0,
"msg": "ok",
"data": [
{ "title": "维护通知", "content": "...", "level": "info", "created_at": "2026-10-11 00:00:00" }
]
}
<?php
$appKey = 'AK5B02D5D6B2A77372';
$appSecret = '你的AppSecret';
$deviceId = '设备唯一标识';
$code = 'GZ-XXXX-XXXX-XXXX';
$ts = time();
$sign = md5($appKey . $deviceId . $ts . $appSecret);
$data = [
'app_key' => $appKey,
'device_id' => $deviceId,
'timestamp' => $ts,
'sign' => $sign,
'code' => $code,
];
$ch = curl_init('http://your-domain/api/activate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
]);
$resp = json_decode(curl_exec($ch), true);
if ($resp['code'] === 0) {
echo '激活成功,到期:' . $resp['data']['expire_at'];
} else {
echo '失败:' . $resp['msg'];
}
import time, hashlib, requests
app_key = "AK5B02D5D6B2A77372"
app_secret = "你的AppSecret"
device_id = "设备唯一标识"
code = "GZ-XXXX-XXXX-XXXX"
ts = str(int(time.time()))
sign = hashlib.md5((app_key + device_id + ts + app_secret).encode()).hexdigest()
data = {
"app_key": app_key, "device_id": device_id,
"timestamp": ts, "sign": sign, "code": code,
}
resp = requests.post("http://your-domain/api/activate", json=data).json()
print(resp)
const crypto = require('crypto');
const appKey = 'AK5B02D5D6B2A77372';
const appSecret = '你的AppSecret';
const deviceId = '设备唯一标识';
const code = 'GZ-XXXX-XXXX-XXXX';
const ts = Math.floor(Date.now() / 1000).toString();
const sign = crypto.createHash('md5')
.update(appKey + deviceId + ts + appSecret).digest('hex');
fetch('http://your-domain/api/activate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
app_key: appKey, device_id: deviceId,
timestamp: ts, sign, code
})
}).then(r => r.json()).then(console.log);
| code | 说明 |
|---|---|
| 0 | 成功 |
| 400 | 参数不完整或非法 |
| 401 | 签名校验失败 / 请求已过期 |
| 403 | 卡密被封禁 / 已过期 / 设备未绑定 / 设备数已达上限 |
| 404 | 应用或卡密不存在 |
| 429 | 请求过于频繁(触发频率限制) |
| 500 | 服务器内部错误 |
请确认 AppSecret 正确、拼接顺序为
app_key + device_id + timestamp + app_secret,且结果为小写 MD5。
客户端系统时间与服务器时间误差过大。请校准时间,误差需在系统设置的「时钟误差」范围内。
在控制台「设备管理」中将旧设备踢下线,即可释放绑定名额。
每次成功调用 /api/verify 计一次,次数耗尽后卡密自动失效。