请求签名校验
1.签名前准备
假设所有发送或者接收到的参数为集合P,将集合P内的非空参数按照参数名的ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串S。 当value类型为JSON时,继续按照JSON key升序排序,将结果添加到排序后的字符串中。当value类型为JSON数组时,逐个获取元素,然后按照JSON key升序排序,将结果添加到排序后的字符串中。
特别注意以下重要规则:
参数名ASCII码从小到大排序(字典序)。
参数名区分大小写。
集合P内的空值null和空字符串(””)都不参与加签。
验证调用返回或 EtsyPay 主动通知签名时,传送的sign参数不参与签名,验证时将生成的签名与该sign值作校验。
sign值区分大小写,统一使用小写。
2.加签
在字符串S最后拼接上key(EtsyPay给商户分配的密钥),得到字符串signTemp并对signTemp进行MD5运算,最终得到完成加签的值signValue。
3.加签示例(商户请求参数加签)
假设传送的参数如下:
params = {
"tradeNo": "10012021010314463575400004",
"merchantId": "153311",
"customer": {
"phone": "0818064342",
"name": "jack"
},
"item": [{
"id": 100114,
"product": "test1",
"amount": 5000
},{
"id": 100117,
"product": "test2",
"amount": 10000
}]
}商户密钥为:merchant-key。
首先按照最外层从小到大排序:
1."customer":{"phone": "0818064342","name": "jack"}
2."item":[{"id": 100114,"product": "test1","amount": 5000},{"id": 100117,"product": "test2","amount": 10000}]
3."merchantId":"153311"
4."tradeNo":"10012021010314463575400004"对第1部分customer进行排序,其类型是JSON,按照JSON key进行升序排序得到字符串:
name=jack&phone=0818064342对第2部分item进行排序,其类型是JSON数组,逐个获取元素,然后按照JSON key升序排序并拼接到最后得到字符串:
name=jack&phone=0818064342&amount=5000&id=100114&product=test1&amount=10000&id=100117&product=test2将第3、4部分转换成key=value格式并拼接到最后得到字符串:
name=jack&phone=0818064342&amount=5000&id=100114&product=test1&amount=10000&id=100117&product=test2&merchantId=153311&tradeNo=10012021010314463575400004生成签名
S = "name=jack&phone=0818064342&amount=5000&id=100114&product=test1&amount=10000&id=100117&product=test2&merchantId=153311&tradeNo=10012021010314463575400004";
获取签名(其中获取字符串md5值方法为:MD5() ):
signTemp = S + "merchant-key"
sign = MD5(signTemp) //加签后的值"e756a16616c82b0e9f63f83217165de9"组装请求参数
params = {
"tradeNo": "10012021010314463575400004",
"merchantId": "153311",
"customer": {
"phone": "0818064342",
"name": "jack"
},
"item": [{
"id": 100114,
"product": "test1",
"amount": 5000
},{
"id": 100117,
"product": "test2",
"amount": 10000
}],
"sign": "e756a16616c82b0e9f63f83217165de9"
}4.验签示例(商户接受 EtsyPay 服务端回调通知或请求响应)
注意:签名规则同上,sign参数不参与签名。 如回调请求为:
{
"amount":"325000",
"merchantId":"100011",
"orderNo":"CTP92523920220104002031",
"payState":"00",
"returnCode":"200",
"returnMsg":"success",
"sign":"eb610f4e17a1f3041c10b5b4d258bef6",
"tradeNo":"10012021010323203164700003",
"type":1
}则需验签的参数如下:
{
"amount":"325000",
"merchantId":"100011",
"orderNo":"CTP92523920220104002031",
"payState":"00",
"returnCode":"200",
"returnMsg":"success",
"tradeNo":"10012021010323203164700003",
"type":1
}商户密钥: key = merchant-key
对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:
S = "amount=325000&merchantId=100011&orderNo=CTP92523920220104002031&payState=00&returnCode=200&returnMsg=success&tradeNo=10012021010323203164700003&type=1";
获取签名(其中获取字符串md5值方法为:MD5() ):
signTemp= S + "merchant-key"
newSign = MD5(signTemp)//加签后的值"eb610f4e17a1f3041c10b5b4d258bef6"比对签名 判断响应或者请求参数sign是否等于newSign,是则验签通过。
5.签名代码样例
public static String createSign(JSONObject jsonObject, String merchantKey){
try {
List<String> keyValuePairs = new ArrayList<>();
Map<String, Object> sortedMap = new TreeMap<>(jsonObject);
for (Map.Entry<String, Object> entry : sortedMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof JSONObject) {
JSONObject innerJsonObject = (JSONObject) value;
String innerString = convertToString(innerJsonObject);
keyValuePairs.add(innerString);
} else if (value instanceof JSONArray) {
JSONArray jsonArray = (JSONArray) value;
List array = new ArrayList();
for (Object item : jsonArray) {
if (item instanceof JSONObject) {
JSONObject innerJsonObject = (JSONObject) item;
String innerString = convertToString(innerJsonObject);
keyValuePairs.add(innerString);
} else {
array.add(item);
}
}
if (array.size() > 0) {
Object[] items = array.toArray();
Arrays.sort(items);
String result = StringUtils.join(items, ",");
if (StringUtils.isNotEmpty(result)) {
keyValuePairs.add(key + "=" + result);
}
}
} else {
String stringValue = Objects.toString(value, "");
if (StringUtils.isNotEmpty(stringValue)) {
keyValuePairs.add(key + "=" + stringValue);
}
}
}
String waitingSignStr = String.join("&", keyValuePairs);
sign = MD5Util.getMD5String(waitingSignStr + merchantKey);//MD5加密
return sign;
} catch (Exception e) {
return null;
}
}
Last updated