由于支付宝公布新签约商户MD5密钥整改通知,MD5密钥到2022-5-18后会失效。
image.png
所以最近公司老旧的Android项目都要升级一遍。在和.net后端同事对接中就出现了验签异常的事故。由于验签失败,支付宝回调商户服务端通知后,商户服务端验签失败无法对订单状态做处理。其中最容易导致验签失败的原因就是解密的秘钥用错了,需要使用支付宝公钥
。
支付宝加签方式有三种:MD5,RSA,RSA2。现在推荐RSA2加签,MD5将要失效,APP的RSA秘钥设置入口已经封闭了,但是mapi网关的还保留着。
1、什么是支付宝公钥:
支付宝公钥有多种,每一种网关对应不同的支付宝公钥
,这里容易对开发者造成误导,容易拿错支付宝公钥。支付宝支付中实行私钥加签,公钥验签的方式保证安全性。
image.png
- 客户端APP——开发平台秘钥(每个应用都需要自己设置对应的商户公钥,才能获取查看到支付宝公钥)
开发平台秘钥
- web网站——mapi网关秘钥
mapi网关秘钥
- 测试环境——沙箱应用秘钥
沙箱应用秘钥
如何生成公钥和私钥?使用支付宝秘钥工具生成 如何获取支付宝公钥?获取不同环境网关下的公钥 开放平台密钥, mapi网关产品密钥,老版wap支付密钥的区别
2、交易流程:
image.png
由上图可以知道,支付宝交易流程: 1.APP客户端使用商户私钥对订单参数加签完成后调用SDK后与支付宝服务端对接 2.支付宝服务端使用商户上传的商户公钥进行验签 3.支付宝验签成功后使用支付宝私钥对支付结果进行加签后,异步回调支付结果到商户订单中的回调响应地址处。同时APP客户端拿到支付宝同步信息,我们可以使用支付宝开发平台开发者助手对支付宝同步信息进行同步验签操作,验证数据准确性。推荐是异步验签为准。 4.商户服务端拿到回调地址中支付宝返回的最原始订单结果数据后,使用支付宝公钥进行异步验签操作,验签成功后执行商户自己的订单结果处理 5.还有一点,支付宝私钥是用于加密支付宝返回商户的数据通知,不对外公布,无法获取
3、APP实现异步验签——java方式:
- 服务端SDK下载
- 将下载的jar包导入新项目中
- 使用支付宝回调商户服务端最原始的数据,不用在意手机号脱敏等问题,使用工具utf-8还原一下编码
- 验签过程中遇到工具异步验签一直失败,代码异步验签成功的情况,支付宝技术支持推荐以代码验签为准
异步验签代码事例如下:
//回调的待验签字符串,含带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");
}
同步验签
4、验签失败原因: 同步验签失败 异步验签失败
image.png
注意:
- 最好使用最新的服务端SDK验签,我在对接中就出现了后端大佬使用旧SDK对接导致一直验签失败的痛苦过程
- APP客户端应用需要在开放平台秘钥栏目设置对应应用的加签方式,才能获取的到支付宝公钥
- 检查使用的支付宝公钥是否拿的是正确的,APP客户端使用的是对应应用上的支付宝公钥
- 支付无法调起的话,别忘了在你的应用详情,“能力管理”中添加“能力列表”里的“APP支付”能力
- 确认多处的APPID,别使用错了
- web网站直接使用mapi网关处的支付宝公钥