# 接入须知

泡椒云网络验证支持多平台、多终端、多开发环境,此文档将帮助你将泡椒云网络验证的功能集成到你的应用或脚本中。

# 签名算法(sign)

# 计算公式

sign = md5(http_method + host + path + k1=v1&k2=v2&kn=vn + app_secret)
1

注意

参数必须按照顺序放置

参数名 参数说明
http_method 请求方法,GET或POST
host 域名,例如:api.paojiaoyun.com
path 地址,例如:/v1/card/login
k1=v1...kn=vn 1.将全部请求参数格式化成k=v
2.将格式化后的参数按升序排列,然后用&符号相隔拼接在一起,不想写排序代码也可严格按照接口文档中的请求参数表写死顺序
(注意:1.不包括sign参数, 2.V不应进行url encode)
app_secret 软件秘钥,在开发端后台软件列表获取

# 以调用卡密登录接口举例

POST 请求 https://api.paojiaoyun.com/v1/card/login

伪代码如下:

app_secret = "uiS9M0G8JolpUvlf5NxZ7pwMVinKs73x"  # 软件秘钥
http_method = "POST"
host = "api.paojiaoyun.com"
path = "/v1/card/login"

# 参数列表:
#  app_key=blsvh14llhcr96vtboqg
#  card=abc3b65KDZ9Qb7UC685D2MVFR0TPc53BCU1IPD5ad20
#  device_id=123
#  nonce=359c22e4-d522-4771-ba8e-4b99cf61b372
#  timestamp=1574654197
# 将以上格式化的参数排序后,用 & 符号相隔拼接起来
params = "app_key=blsvh14llhcr96vtboqg&card=abc3b65KDZ9Qb7UC685D2MVFR0TPc53BCU1IPD5ad20&device_id=123&nonce=359c22e4-d522-4771-ba8e-4b99cf61b372&timestamp=1574654197"

# 带入计算公式
sign = md5(http_method + host + path + params + app_secret)

print(sign)  # 输出 b5f3cc619998fa45e4c11ef57e712f87
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 公共参数详细释义

  • timestamp:当前时间戳,保证签名只在1分钟内有效,请求到达服务器后会将时间戳参数与当前服务器时间相比较,是否超过了60s。防止别有用心的人抓包并重放请求。
  • nonce:不超过36位的随机字符串(建议用UUID),对于当前软件,服务器会记录每次请求的nonce,如果在60s内出现第二次,则会拒绝该请求。用于配合时间戳避免重放攻击。

# 双向签名

目前所有接口已支持双向签名,接口调用成功后,会额外返回noncesign两个字段,nonce服务端保证不会有重复的返回,sign用来保证服务端响应内容不被篡改。
自己封装接口的开发者可以参考下面的服务端签名规则:

sign = md5(code + message + k1=v1&k2=v2&kn=vn + nonce + app_secret)
1

伪代码如下:

app_secret = "uiS9M0G8JolpUvlf5NxZ7pwMVinKs73x"  # 软件秘钥
prev_nonce = None  # 全局变量,用以记录服务端返回的nonce


def check_resp_sign(resp):
    if prev_nonce == None:  # 第一次请求
        prev_nonce = resp['nonce']
    else if resp['nonce'] == prev_nonce: # 跟上一次服务端返回的nonce对比,如果相同则可判定为异常请求
        return False

    result = resp.get('result', {})  # {'expires': '2020-10-16 00:47:58', 'expires_ts': 1602780478, 'server_time': 1579598162}
    
    params = []
    # 将响应中的result中的所有字段按 k=v 的形式组合
    for k, v in result.items():
        params.append(f'{k}={v}')
    # 排序
    params = sorted(params)  # ['expires=2020-10-16 00:47:58', 'expires_ts=1602780478', 'server_time=1579598162']
    # 用 & 符号相隔拼接起来
    pstr = '&'.join(params)  # expires=2020-10-16 00:47:58&expires_ts=1602780478&server_time=1579598162
    # 将所有参与签名的参数按规则拼接起来
    ss = f"{resp['code']}{resp['message']}{pstr}{resp['nonce']}{app_secret}" # 0okexpires=2020-10-16 00:47:58&expires_ts=1602780478&server_time=1579598162bojc2kiuof2jci9b90jguiS9M0G8JolpUvlf5NxZ7pwMVinKs73x
    # 本地签名
    resp_sign = md5(ss.encode()).hexdigest()  # 4954c9805d4040a95336150e6e5f14e2
    return resp_sign == resp['sign']  # 对比签名是否一致


resp = card_heartbeat()  # {"code":0,"message":"ok","result":{"expires":"2020-10-16 00:47:58","expires_ts":1602780478,"server_time":1579598162},"nonce":"bojc2kiuof2jci9b90jg","sign":"4954c9805d4040a95336150e6e5f14e2"}
check_resp_sign(resp)  # True / False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 接口返回码对照表

返回码 说明
0 调用成功
400 参数错误,请检查请求参数,详细字段错误会通过errs返回
404 资源未找到
500 服务器错误,请稍后重试
10010 无效的签名,请检查签名算法
10011 签名已过期,签名只在1分钟内有效
10013 时间戳大于当前服务器时间,请检查timestamp参数
10210 卡密已过期
10212 卡密已被冻结
10213 卡密超过多开上限
10214 登录状态已失效,可能原因:超时未发心跳包、被挤下线、后台冻结、卡用户修改密码。
10230 软件不存在,请检查app_key
10240 卡密不存在或已被使用
10241 卡密已被使用
10242 账号已存在,用户注册时返回
10243 用户登录密码错误
10250 用户已到期
10252 用户已被冻结
10253 用户超过多开上限
10254 解绑密码不正确
10304 已经是最新版本,获取软件最新版本返回
10401 软件未开启试用,开发者需在后台软件管理配置
10402 试用中,请勿重复登录
10403 已试用过了
10404 请先登录,原因:未登录就调用心跳接口或者登录后超过60秒再调用心跳接口
10405 试用已到期,软件配置为一次性试用,心跳接口返回
10406 本周期试用已到期,软件配置为间隔试用,心跳接口返回
10501 远程变量不存在
10521 远程数据不存在
10522 远程数据key已存在
10541 远程函数不存在
10542 参数(params)必须为json列表序列化后的string