Handle 业务调用
Handle 是 A7验证两步模型的第二步:所有业务能力(登录、注册、心跳、查询、续期等)都通过这一个接口调用,具体执行哪个业务由加密明文中的 action 字段决定。
| 项目 | 值 |
|---|---|
| 请求方式 | POST |
| 请求地址 | https://api.a7p.cn/api/verify/{ApiPassword} |
| Content-Type | application/x-www-form-urlencoded |
| 是否加密 | 是,业务参数经 RC4 加密后转 HEX 大写 |
| 时间戳窗口 | ±300 秒 |
调用步骤
- 先完成 Init 握手,拿到
ApiPassword。 - 拼接业务明文参数串:
action=业务名&参数1=值1&参数2=值2,action放首位。 - 用
ApiPassword作为密钥对明文做 RC4 加密,密文字节转 HEX 大写,得到Data。 - 取当前 Unix 秒级时间戳
TimeStamp。 - 计算
Sign = MD5(ApiPassword + TimeStamp + Data)。 - 表单
POST到https://api.a7p.cn/api/verify/{ApiPassword},提交TimeStamp、Data、Sign。 - 解析响应 JSON,
code == 200为成功,其余按错误码处理。
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
TimeStamp | string | 是 | Unix 秒级时间戳,±300 秒有效 |
Data | string | 是 | RC4(ApiPassword, 明文参数) 后转 HEX 大写 |
Sign | string | 是 | MD5(ApiPassword + TimeStamp + Data) |
ApiPassword | string | 否 | 接口密码。可从 URL 路径传,也可用请求体字段或请求头传,三选一 |
ApiPassword 的三种传递方式
服务端按以下优先级读取接口密码:
| 优先级 | 方式 | 写法 | 推荐度 |
|---|---|---|---|
| 1 | 请求头 | X-Api-Password: A1B2C3... | 推荐,不会写进访问日志 / 浏览器历史 |
| 2 | 请求体字段 | 表单里加 ApiPassword=A1B2C3... | 可用 |
| 3 | URL 路径 | POST /api/verify/A1B2C3... | 兼容旧客户端,明文出现在 URL 中 |
老客户端兼容
URL 路径写法仍然可用,路径段匹配正则 [A-Z0-9]{0,32}(大写字母与数字,最长 32 位)。新项目建议改用请求头 X-Api-Password,避免接口密码被 nginx access_log 记录。
Data 明文格式
解密后的明文是标准的 URL 查询串格式,用 & 连接键值对:
text
action=SingleLogin&Card=XXXX-XXXX-XXXX-XXXX&Mac=MAC001&DeviceName=MyPC| 规则 | 说明 |
|---|---|
action 位置 | 建议放首位;服务端用 parse_str 解析,其余键值对顺序不影响结果 |
action 大小写 | 区分大小写,必须与文档完全一致,如 UserRegin 不是 UserRegist |
| 值中含特殊字符 | 若参数值可能包含 & = % 等字符,请先做 URL 编码再拼接 |
| 编码 | 明文按 UTF-8 编码后再做 RC4 |
请求示例
python
import hashlib
import json
import time
import urllib.request
BASE = "https://api.a7p.cn/api/verify"
def rc4(key: str, data: str) -> str:
"""RC4 加密,返回 HEX 大写字符串。"""
key_bytes = key.encode("utf-8")
s = list(range(256))
j = 0
for i in range(256):
j = (j + s[i] + key_bytes[i % len(key_bytes)]) % 256
s[i], s[j] = s[j], s[i]
i = j = 0
out = bytearray()
for b in data.encode("utf-8"):
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])
return out.hex().upper()
def handle(api_pw: str, plain: str) -> dict:
"""通用 Handle 调用:传入 ApiPassword 与明文参数串,返回响应字典。"""
ts = int(time.time())
data_hex = rc4(api_pw, plain)
sign = hashlib.md5(f"{api_pw}{ts}{data_hex}".encode("utf-8")).hexdigest()
body = f"TimeStamp={ts}&Sign={sign}&Data={data_hex}".encode("utf-8")
req = urllib.request.Request(
BASE,
data=body,
headers={
"Content-Type": "application/x-www-form-urlencoded",
"X-Api-Password": api_pw, # 推荐:用请求头传接口密码
},
)
with urllib.request.urlopen(req, timeout=10) as resp:
return json.loads(resp.read().decode("utf-8"))
# 用法
result = handle("A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6",
"action=GetBulletin")
print(result)csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public sealed class A7Client
{
private const string Base = "https://api.a7p.cn/api/verify";
private readonly HttpClient _http = new HttpClient
{
Timeout = TimeSpan.FromSeconds(10)
};
private readonly string _apiPassword;
public A7Client(string apiPassword) => _apiPassword = apiPassword;
public static string Rc4(string key, string data)
{
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] dataBytes = Encoding.UTF8.GetBytes(data);
int[] s = new int[256];
for (int i = 0; i < 256; i++) s[i] = i;
int j = 0;
for (int i = 0; i < 256; i++)
{
j = (j + s[i] + keyBytes[i % keyBytes.Length]) % 256;
(s[i], s[j]) = (s[j], s[i]);
}
var sb = new StringBuilder(dataBytes.Length * 2);
int x = 0, y = 0;
foreach (byte b in dataBytes)
{
x = (x + 1) % 256;
y = (y + s[x]) % 256;
(s[x], s[y]) = (s[y], s[x]);
sb.Append((b ^ s[(s[x] + s[y]) % 256]).ToString("X2"));
}
return sb.ToString();
}
public static string Md5(string text)
{
using var md5 = MD5.Create();
byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(text));
var sb = new StringBuilder(32);
foreach (byte b in hash) sb.Append(b.ToString("x2"));
return sb.ToString();
}
/// <summary>通用 Handle 调用。plain 为 action=...&k=v 明文串。</summary>
public async Task<JsonElement> HandleAsync(string plain)
{
long ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
string dataHex = Rc4(_apiPassword, plain);
string sign = Md5($"{_apiPassword}{ts}{dataHex}");
using var req = new HttpRequestMessage(HttpMethod.Post, Base)
{
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["TimeStamp"] = ts.ToString(),
["Sign"] = sign,
["Data"] = dataHex
})
};
req.Headers.Add("X-Api-Password", _apiPassword);
using HttpResponseMessage resp = await _http.SendAsync(req);
string body = await resp.Content.ReadAsStringAsync();
return JsonDocument.Parse(body).RootElement.Clone();
}
}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...支持的 action 一览
Handle 共支持 12 个业务 action:
| action | 中文名 | 文档 |
|---|---|---|
SingleLogin | 卡密登录 | 查看 |
UserLogin | 用户登录 | 查看 |
UserRegin | 用户注册 | 查看 |
UpdatePwd | 修改密码 | 查看 |
ChangeBind | 换绑设备 | 查看 |
UserHeartbeat | 心跳检测 | 查看 |
GetLatestVersion | 获取最新版本 | 查看 |
GetBulletin | 获取程序公告 | 查看 |
GetVariable | 获取远程变量 | 查看 |
GetUserInfo | 获取用户信息 | 查看 |
GetCardInfo | 获取卡密信息 | 查看 |
UserRecharge | 用户充值续期 | 查看 |
传入列表之外的 action 会返回 1015 未知操作: xxx。
通用失败响应
以下错误在任何 action 之前就会返回,属于传输层校验失败:
json
{ "code": 1001, "message": "程序不存在", "data": null }json
{ "code": 1010, "message": "签名错误", "data": null }json
{ "code": 1012, "message": "程序未审核通过", "data": null }json
{ "code": 1013, "message": "参数不完整", "data": null }json
{ "code": 1014, "message": "时间戳已过期", "data": null }json
{ "code": 1015, "message": "未知操作: XXX", "data": null }错误码
| 错误码 | 含义 | 解决方案 |
|---|---|---|
1001 | 程序不存在 | ApiPassword 无效或拼错,重新走一次 Init |
1010 | 签名错误 | 核对 MD5(ApiPassword + TimeStamp + Data);确认 Data 已转 HEX 大写;确认签名用的 TimeStamp 与提交的一致 |
1012 | 程序未审核通过 | 产品状态异常或套餐过期 |
1013 | 参数不完整 | TimeStamp 或 Sign 缺失 |
1014 | 时间戳已过期 | 校准本机时间 |
1015 | 未知操作 | action 拼写错误或大小写不对;也可能是 RC4 解密失败导致明文乱码 |
完整列表见错误码对照表。
相关文档
- Init 初始化握手 —— 第一步:换取 ApiPassword
- API 概述 · 两步模型 —— 协议全貌
- 防重放攻击实战 —— 时间戳窗口与幂等设计
- SDK 实现:易语言 · C# · Python · Go