# 接入须知

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

# 签名算法(sign)

# 计算公式

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

注意

参数必须按照顺序放置

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

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

POST 请求https://api1.7ccccccc.com/v1/card/login

伪代码如下:

appSecret = "H8BNIyZRkJBEzwmyYXMIVsQzuCqMgANx"  # 软件秘钥
httpMethod = "POST"
host = "api1.7ccccccc.com"
path = "/v1/card/login"

# 参数列表:
#  app_key=CTbGa7o25zST4xAmHi
#  card=dygffGL1hzusjXxcddgBYB
#  device_id=91ebd72571d69bb8
#  nonce=phqghumeaylnlfdxfirc
#  timestamp=1693051742063
# 将以上格式化的参数排序后,用 & 符号相隔拼接起来
params = "appKey=CTbGa7o25zST4xAmHi&card=dygffGL1hzusjXxcddgBYB&device_id=91ebd72571d69bb8&nonce=phqghumeaylnlfdxfirc&timestamp=1693051742063"

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

print(sign)  # 输出 0814f9198def92c4d7ceaf9f9795e486
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内出现第二次,则会拒绝该请求。用于配合时间戳避免重放攻击。 hgfhgfhg

# 双向签名

目前所有接口已支持双向签名,接口调用成功后,会额外返回noncesign两个字段,nonce服务端保证不会有重复的返回,且nonce是趋势递增的(也就是说本次请求响应的nonce肯定是大于上一次次请求响应的nonce),sign用来保证服务端响应内容不被篡改。 自己封装接口的开发者可以参考下面的服务端签名规则:

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

伪代码如下:

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


def check_resp_sign(resp):
    if prev_nonce == None:  # 第一次请求
        prev_nonce = resp['nonce']
    else if resp['nonce'] <= prev_nonce: # 跟上一次服务端返回的nonce对比,如果本次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']}{appSecret}" # 0okexpires=2020-10-16 00:47:58&expires_ts=1602780478&server_time=1579598162bojc2kiuof2jci9b90jgH8BNIyZRkJBEzwmyYXMIVsQzuCqMgANx
    # 本地签名
    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 参数错误,缺少appKey参数
10011 签名已过期,签名只在1分钟内有效且是一次性的
10012 软件不存在,请检查appKey
10013 无效的签名,请检查签名算法
10014 参数错误,缺少token参数
10015 访问太频繁,禁止访问
10016 登录状态已失效
10017 无效的appKey
10018 卡密不存在
10019 卡密不可用(卡密不存在)
10020 卡密已过期
10021 卡密已被冻结
10022 超出可绑定设备上限
10023 卡密超过多开上限
10024 卡密已在其他地方登陆
10025 没有此卡密
10026 卡密-设备号已在其他地方登陆
10027 卡密已被冻结
10028 card卡密不可用
10029 该软件不可解绑设备
10030 未使用的卡密不可解绑设备
10031 useCard卡密不可用
10032 该卡密不可解绑设备
10033 解绑密码不正确
10034 该卡密不属于该软件
10035 卡密已经过期,不能充值
10036 未使用过的卡密不能充值
10037 用户名长度太长
10038 账号已存在
10039 未使用过的卡密才能注册
10040 账号不存在
10041 用户登录密码错误
10042 用户已过期
10043 用户已被冻结
10044 用户超过多开上限
10045 用户超出可绑定设备上限
10046 用户已在其他地方登陆
10047 用户不可用
10048 用户-设备号已在其他地方登陆
10050 该卡密不属于该软件
10051 缺少数据值
10052 数据名不能超过64个字符
10053 数据值不能超过256个字符
10054 已经存在同名数据无法创建
10056 软件未开启试用
10057 已试用过了
10058 本周期试用已到期
10059 试用已到期