-
10周年大促!注册即领300元优惠券
- 注册/登录
参数名 | 类型 | 说明 |
app_key | string(32) | 人人秀平台分配的AppKey |
time_stamp | string(14) | 1970-01-01开始的时间戳,精确到毫秒 |
sign | string(32) | 根据签名算法计算所得 |
特别注意以下重要规则:
人人秀平台使用PHP语言作为签名系统生成算法,使用Java等不同语言在处理汉字编码、MD5加密可能有差异导致签名不一致,MD5位数为32位;
假设某接口需要传送如下信息:
openid: ot1UbuBBzlE6IjEDWfyXQW3dy2S4
transaction_no: 69201704060281699381
time_stamp: 1543999047492
nonce_str: ibuaiVcKdpRxkhJA
order_no: 19201704060281699381
按照API接口规范,实际需要传递信息为:
app_key: 96c84928b1dce057d110ea3b3880fc83
time_stamp: 1543999047492
sign:
openid: ot1UbuBBzlE6IjEDWfyXQW3dy2S4
transaction_no: 69201704060281699381
nonce_str: ibuaiVcKdpRxkhJA
order_no: 19201704060281699381
按照签名算法计算sign:
第1步:对参数按照key=value的格式 stringA="app_key=96c84928b1dce057d110ea3b3880fc83&nonce_str= ibuaiVcKdpRxkhJA&openid=ot1UbuBBzlE6IjEDWfyXQW3dy2S4&order_no= 19201704060281699381&time_stamp=1543999047492&transaction_no=69201704060281699381";
第2步:拼接AppSecret
sign=MD5(stringSignTemp).toUpperCase() //得到C17482AB45EA3C724CB648223ED8E2D2
最后得到最终发送的数据:
app_key: 96c84928b1dce057d110ea3b3880fc83
time_stamp: 1543999047492
sign:
openid: ot1UbuBBzlE6IjEDWfyXQW3dy2S4
transaction_no: 69201704060281699381
nonce_str: ibuaiVcKdpRxkhJA
order_no: 19201704060281699381
必须在服务器端计算签名
客户端⽣成签名地址,可能会导致以下问题:
1.客户端易被破解,AppSecret有外泄的⻛险,危害严重!
签名过期检查
由⼈⼈秀对商户平台发起的请求,请求参数⾥会有time_stamp(时间戳字段),请商户平台务必根据此字段对请求的签名做过期处理,⼈⼈秀平台建议过期时间为10分钟。
签名失败的问题排查
// 计算签名类
class RrxAPI
{
protected $values = array();
public function __construct($data=array())
{
foreach ($data as &$d){
// 参数解码
$d = urldecode($d);
}
$this->values = $data;
}
/**
* 签名生成算法
* @param string $secret API密钥
* @return string 签名
*/
public function makeSign($secret){
//签名步骤一:按字典序排序参数
ksort($this->values);
$string = $this->ToUrlParams();
//签名步骤二:在string后加入app_secret
$string = $string . "&app_secret=".$secret;
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
/**
* 格式化参数格式化成url参数
*/
private function ToUrlParams()
{
$buff = "";
foreach ($this->values as $k => $v)
{
// 排除签名参数sign 、空值 、 数组
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
}
// 调用签名方法,计算签名
$query_data=[
'app_key'=>'test_app_key',
'openid'=>'test_openid',
'time_stamp'=>'1543999047492',
'name'=>'张飞'
];
$apiSdk = new RrxAPI($query_data);
$secret = 'test_secret';
$sign=$apiSdk->makeSign($secret);
得到签名为 8F4CC38010A6F917E788ED99518BD589
import cn.hutool.core.collection.CollUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import java.util.TreeMap;
public class RrxAPI {
// 开通API,获取key
private static final String appKey = "test_app_key";
// 开通API,获取Secret
private static final String appSecret = "test_secret";
public static void main(String[] args) {
JSONObject paramObj = new JSONObject();
String timestamp = "1543999047492";
String openid = "test_openid";
String name = "张飞";
String emptyStr = "";
paramObj.putOnce("app_key", appKey);
paramObj.putOnce("time_stamp", timestamp);
paramObj.putOnce("openid", openid);
paramObj.putOnce("name", name);
paramObj.putOnce("emptyStr", emptyStr);
paramObj.putOnce("sign", "sign");
String sign = makeSign(paramObj);
System.out.println("最终的签名字符串:" + sign);
}
private static String makeSign(JSONObject paramObj) {
//排除按字典序排序参数
TreeMap<String, Object> sortedParamObj = CollUtil.sort(paramObj, String::compareTo);
StringBuilder signString = new StringBuilder();
sortedParamObj.forEach((key, value) -> {
// 排除签名参数sign 、空值 、 数组
if (key != "sign" && value != "") {
signString.append(key).append("=").append(value).append("&");
}
});
String fullSignString = signString + "app_secret=" + appSecret;
System.out.println("完整的签名字符串:" + fullSignString);
String sign = SecureUtil.md5(fullSignString);
System.out.println("md5加密后:" + sign);
return sign.toUpperCase(); // 转换为大写
}
}
此代码执行结果为 8F4CC38010A6F917E788ED99518BD589