API 概述 · Init + Handle 两步模型
A7验证提供 RESTful API 用于软件授权验证。所有接口均使用 HTTP POST,请求体为 表单格式(application/x-www-form-urlencoded),响应统一为 JSON。
接口采用 两步模型:
- 先调用 Init,用
AppId+AppKey换取本次会话的ApiPassword(接口密码)。 - 再用
ApiPassword对后续所有业务请求做 RC4 加密 + MD5 签名,通过 Handle 接口按明文参数中的action字段分发到具体业务。
这样设计的好处:程序密钥 AppKey 只在握手阶段出现一次,业务请求中不再传输,即使业务流量被抓包也拿不到永久凭据。
基本信息
| 项目 | 说明 |
|---|---|
| Init 接口 | POST https://api.a7p.cn/api/verify |
| Handle 接口 | POST https://api.a7p.cn/api/verify/{ApiPassword} |
| 请求方式 | POST(仅支持 POST) |
| 请求格式 | application/x-www-form-urlencoded |
| 响应格式 | JSON,字符编码 UTF-8 |
| 加密方式 | RC4 对称加密(密文转 HEX) + MD5 签名 |
| 时间戳窗口 | Unix 秒级时间戳,允许 ±300 秒偏差 |
| 业务 action 数量 | 12 个,见下方列表 |
机器码参数写法
机器码参数在本文档中统一写作 Mac。服务端同时兼容 Mac / mac / DeviceId 三种写法,任选其一传入即可。
调用步骤
- 客户端取当前 Unix 秒级时间戳
TimeStamp。 - 计算 Init 签名:
Sign = MD5(AppId + AppKey + TimeStamp + AppKey)。 - 向
POST /api/verify提交AppId、AppKey、TimeStamp、Sign,得到data.api_password。 - 把
api_password保存在内存变量中(不要落盘、不要硬编码)。 - 拼接业务明文参数串,
action置于首位,例如action=SingleLogin&Card=XXXX-XXXX-XXXX-XXXX&Mac=MAC001。 - 用
ApiPassword作为密钥对明文串做 RC4 加密,密文字节转 HEX 字符串得到Data。 - 重新取时间戳,计算 Handle 签名:
Sign = MD5(ApiPassword + TimeStamp + Data)。 - 向
POST /api/verify/{ApiPassword}提交TimeStamp、Data、Sign,解析返回的 JSON。
Step 1 · Init 初始化握手
http
POST /api/verify HTTP/1.1
Host: api.a7p.cn
Content-Type: application/x-www-form-urlencoded
AppId=150018&AppKey=YOUR_APP_KEY&TimeStamp=1780000000&Sign=3f2a...c91b请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
AppId | string | 是 | 程序编号,例如 150018 |
AppKey | string | 是 | 程序密钥(32 位大写字母 + 数字) |
TimeStamp | string | 是 | Unix 秒级时间戳,有效期 ±300 秒 |
Sign | string | 是 | MD5(AppId + AppKey + TimeStamp + AppKey) |
成功响应
json
{
"code": 200,
"message": "success",
"data": {
"api_password": "A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6"
}
}| 字段 | 类型 | 说明 |
|---|---|---|
data.api_password | string | 32 位接口密码,用于后续 Handle 的签名与 RC4 加密 |
失败响应
json
{"code":1013,"message":"参数不完整","data":null}
{"code":1014,"message":"时间戳已过期","data":null}
{"code":1001,"message":"程序不存在","data":null}
{"code":1011,"message":"程序密钥错误","data":null}
{"code":1012,"message":"程序未审核通过","data":null}
{"code":1010,"message":"签名错误","data":null}完整含义见 错误码对照表。
Step 2 · Handle 业务调用
所有业务能力(登录、注册、心跳、查询等)都通过此接口调用。具体业务由 加密后的明文参数中的 action 字段 决定。
http
POST /api/verify/A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6 HTTP/1.1
Host: api.a7p.cn
Content-Type: application/x-www-form-urlencoded
TimeStamp=1780000000&Sign=8d41...7a2e&Data=1F3B7C90AE...请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
TimeStamp | string | 是 | Unix 秒级时间戳,有效期 ±300 秒 |
Data | string | 是 | RC4(ApiPassword, 明文参数串) 后转 HEX 字符串 |
Sign | string | 是 | MD5(ApiPassword + TimeStamp + Data) |
ApiPassword 的三种传递方式
服务端按以下优先级取 ApiPassword:
- 请求头
X-Api-Password(推荐,不会写进访问日志/浏览器历史) - 表单字段
ApiPassword - URL 路径段
/api/verify/{ApiPassword}(兼容旧客户端)
http
POST /api/verify HTTP/1.1
Host: api.a7p.cn
Content-Type: application/x-www-form-urlencoded
X-Api-Password: A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6
TimeStamp=1780000000&Sign=8d41...7a2e&Data=1F3B7C90AE...Data 解密后的明文参数格式
& 连接的键值对,action 建议放在首位:
text
action=SingleLogin&Card=XXXX-XXXX-XXXX-XXXX&Mac=MAC001&DeviceName=MyPC通用失败响应
json
{"code":1001,"message":"程序不存在","data":null}
{"code":1012,"message":"程序未审核通过","data":null}
{"code":1013,"message":"参数不完整","data":null}
{"code":1014,"message":"时间戳已过期","data":null}
{"code":1010,"message":"签名错误","data":null}
{"code":1015,"message":"未知操作: Xxx","data":null}签名注意事项
| 要点 | 说明 |
|---|---|
| MD5 结果大小写 | 服务端按字符串严格比对,推荐统一使用 小写 32 位 |
| RC4 密文编码 | 密文字节需转为 HEX 字符串(推荐 大写)后作为 Data 提交,服务端解析大小写均可 |
| 时间戳 | Unix 秒级(不是毫秒),服务端允许 ±300 秒偏差,超出返回 1014 |
| 参数顺序 | 明文参数中 action 建议置于首位,其余键值对顺序不影响解析 |
| ApiPassword | 32 位接口密码,仅在内存中保存,切勿硬编码或明文落盘 |
| 特殊字符 | 明文参数值若含 & = 等符号,需先做 URL 编码再拼接 |
详细原理见 签名校验与 RC4 加密。
cURL 调试助手
Handle 阶段需要 RC4 加密,纯 shell 实现比较麻烦。下面这段脚本定义了一个 a7call 函数,把它粘进终端后就能用一行命令调用任意 action —— 各 API 页的 cURL 示例都基于它。
bash
# ===== A7验证 cURL 调试助手 =====
# 依赖:curl、python3、md5sum(macOS 用 `md5 -q` 替换 md5sum)
export A7_BASE="https://api.a7p.cn/api/verify"
export A7_APP_ID="150018"
export A7_APP_KEY="YOUR_APP_KEY"
# 1) Init 握手,把 ApiPassword 存进环境变量 A7_PW
a7init() {
local ts sign resp
ts=$(date +%s)
sign=$(printf '%s%s%s%s' "$A7_APP_ID" "$A7_APP_KEY" "$ts" "$A7_APP_KEY" | md5sum | cut -d' ' -f1)
resp=$(curl -s -X POST "$A7_BASE" \
-d "AppId=${A7_APP_ID}" -d "AppKey=${A7_APP_KEY}" \
-d "TimeStamp=${ts}" -d "Sign=${sign}")
echo "Init => $resp"
export A7_PW=$(printf '%s' "$resp" | python3 -c \
"import sys,json;print(json.load(sys.stdin).get('data',{}).get('api_password',''))")
echo "A7_PW=$A7_PW"
}
# 2) Handle 调用,参数为完整明文参数串
a7call() {
local plain="$1" ts data sign
ts=$(date +%s)
data=$(A7K="$A7_PW" A7P="$plain" python3 -c '
import os
k = os.environ["A7K"].encode()
p = os.environ["A7P"].encode()
s = list(range(256)); j = 0
for i in range(256):
j = (j + s[i] + k[i % len(k)]) % 256
s[i], s[j] = s[j], s[i]
i = j = 0
out = bytearray()
for b in p:
i = (i + 1) % 256
j = (j + s[i]) % 256
s[i], s[j] = s[j], s[i]
out.append(b ^ s[(s[i] + s[j]) % 256])
print(out.hex().upper())
')
sign=$(printf '%s%s%s' "$A7_PW" "$ts" "$data" | md5sum | cut -d' ' -f1)
curl -s -X POST "$A7_BASE" \
-H "X-Api-Password: ${A7_PW}" \
-d "TimeStamp=${ts}" -d "Data=${data}" -d "Sign=${sign}"
echo
}用法:
bash
a7init
a7call "action=SingleLogin&Card=UTDE-7TCX-N5AT-ZDSP&Mac=TEST-ABC-123"
a7call "action=GetBulletin"12 个业务 action 列表
| action | 中文名 | 说明 | 文档 |
|---|---|---|---|
SingleLogin | 卡密登录 | 卡密 + 机器码验证,首次使用自动激活并绑定设备 | 查看 |
UserLogin | 用户登录 | 用户名 + 密码登录,支持卡密续期与 QQ 扫码 | 查看 |
UserRegin | 用户注册 | 注册新用户,可同时卡密激活或绑定 QQ | 查看 |
UpdatePwd | 修改密码 | 校验原密码后修改为新密码 | 查看 |
ChangeBind | 换绑机器码 | 校验账号密码后把绑定设备换成新机器码 | 查看 |
UserHeartbeat | 心跳保活 | 维持在线状态并接收后台下发消息 | 查看 |
GetLatestVersion | 获取版本 | 获取最新版本号、更新日志与下载地址 | 查看 |
GetBulletin | 获取公告 | 获取开发者在后台发布的程序公告 | 查看 |
GetVariable | 获取远程变量 | 读取云端配置变量,可取单个或全部 | 查看 |
GetUserInfo | 查询用户信息 | 用户名 + 密码查询注册用户详情 | 查看 |
GetCardInfo | 查询卡密信息 | 通过卡密查询状态、到期时间与绑定详情 | 查看 |
UserRecharge | 用户续期 | 用充值卡密给用户账号续期(无需密码) | 查看 |
只有这 12 个 action
传入列表之外的 action 会返回 1015 未知操作。文档中不存在 webhook、unbind、init(作为 action)等端点。
典型业务流程
卡密模式
Init换取ApiPasswordSingleLogin用卡密 + 机器码登录,拿到token- 缓存
token到内存 - 每 5 分钟
UserHeartbeat(Type=card)
用户账号模式
Init换取ApiPasswordUserRegin注册(可带卡密直接激活)UserLogin登录,拿到token- 每 5 分钟
UserHeartbeat(Type=user) - 到期时
UserRecharge续期,换电脑时ChangeBind换绑