由于支付宝公布新签约商户MD5密钥整改通知,MD5密钥到2022-5-18后会失效。
image.png
所以最近公司老旧的Android项目都要升级一遍。在和.net后端同事对接中就出现了验签异常的事故。由于验签失败,支付宝回调商户服务端通知后,商户服务端验签失败无法对订单状态做处理。其中最容易导致验签失败的原因就是解密的秘钥用错了,需要使用支付宝公钥
。
支付宝加签方式有三种:MD5,RSA,RSA2。现在推荐RSA2加签,MD5将要失效,APP的RSA秘钥设置入口已经封闭了,但是mapi网关的还保留着。
1、什么是支付宝公钥:
支付宝公钥有多种,每一种网关对应不同的支付宝公钥
,这里容易对开发者造成误导,容易拿错支付宝公钥。支付宝支付中实行私钥加签,公钥验签的方式保证安全性。
image.png
开发平台秘钥
mapi网关秘钥
沙箱应用秘钥
如何生成公钥和私钥?使用支付宝秘钥工具生成 如何获取支付宝公钥?获取不同环境网关下的公钥 开放平台密钥, mapi网关产品密钥,老版wap支付密钥的区别
2、交易流程:
image.png
由上图可以知道,支付宝交易流程: 1.APP客户端使用商户私钥对订单参数加签完成后调用SDK后与支付宝服务端对接 2.支付宝服务端使用商户上传的商户公钥进行验签 3.支付宝验签成功后使用支付宝私钥对支付结果进行加签后,异步回调支付结果到商户订单中的回调响应地址处。同时APP客户端拿到支付宝同步信息,我们可以使用支付宝开发平台开发者助手对支付宝同步信息进行同步验签操作,验证数据准确性。推荐是异步验签为准。 4.商户服务端拿到回调地址中支付宝返回的最原始订单结果数据后,使用支付宝公钥进行异步验签操作,验签成功后执行商户自己的订单结果处理 5.还有一点,支付宝私钥是用于加密支付宝返回商户的数据通知,不对外公布,无法获取
3、APP实现异步验签——java方式:
异步验签代码事例如下:
//回调的待验签字符串,含带sign串
String resultInfo = "buyer_id=208****42&total_amount=0.01&body=***试&trade_no=20190329**941025940236¬ify_time=2019-03-29 19:42:04&subject=**电脑网站支付&sign_type=RSA2&charset=UTF-8&auth_app_id=201****222¬ify_type=trade_status_sync&invoice_amount=0.01&out_trade_no=20190329ygyg45484544100003&trade_status=TRADE_SUCCESS&gmt_payment=2019-03-29 19:42:03&version=1.0&point_amount=0.00&sign=LDDUIGQmc+1qNtk3oyoAKVeMUKTngdX3ZjVeZOK0EjiPDJ/+Nk+0WSqcE6J7/5xb96Z/vP0yY3pVhZUiFVJ1G45/ys/HAleHh+EERZ1lkCkule1sSyaGFTKQGKx4uHpTyqIgRB1bouf19RPbSx1EkA0VkCarSy9G/OEG5Qmg8UdL2dRulMhlbOHS7tdMJJycDA8vOspOUMeQmk/H6IK9R2Kou5hN2T3KR1GWLYFK+z1jeZhQB3q52lZynO0OFjSzU4aQUBMW5QskQppBYd/ghtY/2YP+2H6YVGNgVmaheZMQ3PVTBALEV+8rZa91salH9DkKN2UCYGvNSNDT1VGCTQ==&gmt_create=2019-03-29 19:42:00&buyer_pay_amount=0.01&receipt_amount=0.01&fund_bill_list=[{\"amount\":\"0.01\",\"fundChannel\":\"PCREDIT\"}]&seller_id=208****5&app_id=2014100***22¬ify_id=20190329002221942040**8";
//编码格式
String charset="utf-8";
//支付宝公钥
String alipaypublicKey="填入你的支付宝公钥";
//签名方式
String sign_type="RSA2";
//对待签名字符串数据通过&进行拆分
String [] temp = resultInfo.split("&");
LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
//把拆分数据放在map集合内
for (int i = 0; i < temp.length; i++) {
String[] arr = temp[i].split("=", 2); //通过"="号分割成2个数据
String[] tempAagin = new String[arr.length]; //再开辟一个数组用来接收分割后的数据
for (int j = 0; j < arr.length; j++) {
tempAagin[j] = arr[j];
}
map.put(tempAagin[0], tempAagin[1]);
}
System.out.println(map);
//验签方法
boolean signVerified = AlipaySignature.rsaCheckV1(map,alipaypublicKey,charset,sign_type);
if(signVerified){
// TODO 验签成功后
System.out.println("success");
}else{
System.out.println("fail");
}
同步验签
image.png
注意: