自上次解决因为服务器端伪静态导致ecmobile首页无法显示分类问题后,最近又开始弄ecmobile的支付问题。然ecmobile的公开资料不足,或者说我没有找到详细的一些相关设置问题,很多设置和资料都是自己摸索,所以遇到很多问题。
ecmobile的文档说的很清楚了,只需要修改ECMobileAppConst.java中的回调地址和EcmobileManager.java中的相关id,key值就可以使用ecmobile。
查找了一些相关资料,按照自己的理解,设置好了各个参数,生成了apk,之后到手机中测试。
发现支付宝能够支付成功,但是后台还是显示未付款,如图
于是开始了漫长的调试路径。看到这个问题,我第一个反应是回调地址那边有问题,支付成功后没有处理相关订单数据,后来证明这个思路是正确的。于是跑到服务器翻相关文件。
以百蔬网为例,ecmobile的支付宝回调地址是http://www.maiseed.com/ecmobile/payment/alipay/sdk/notify_url.php,
很自然,第一眼就瞄到了这个log.txt,果然在这个文件里面发现重要信息。
集成时请注意:
本文件log.txt请不要删除。
该文本用于写日志函数。
执行日期:20151114202104
验证签名失败
执行日期:20151114202104
验证签名失败
执行日期:20151114210255
rsaVerify:Resource id #33
执行日期:20151114210256
responseTxt=true
notify_url_log:isSign=false,discount=0.00&payment_type=1&subject=揭阳农友 改良益母草 药食同源 活血养颜 益母草种子 10克装等1种商品&trade_no=2015111421001004090091077403&buyer_email=sale@maiseed.com&gmt_create=2015-11-14 21:02:53¬ify_type=trade_status_sync&quantity=1&out_trade_no=2015111458419&seller_id=2088611509453660¬ify_time=2015-11-14 21:02:53&body=揭阳农友 改良益母草 药食同源 活血养颜 益母草种子 10克装等1种商品&trade_status=WAIT_BUYER_PAY&is_total_fee_adjust=Y&total_fee=14.20&seller_email=93845@maiseed.com&price=14.20&buyer_id=2088612797126092¬ify_id=af2539732e351e76a6a25d5b352a555gp0&use_coupon=N&sign_type=RSA&sign=HaidBP6vj6Eu2PzGSte8rjr7nVqavIrwj6A5Fyg/6XkcPTpE2zPdaSnG9wGYRDV4u7g5KiSXt225Asr4iM8d4M/ifgZTH2l6GfosrT3pQzfw6IuXZplo9tP+bTktXphZ1rY+8jLrlRnRbVkiW/Qny9uoLu9BrxQTm1QFhU15qh4=
执行日期:20151114210256
验证签名失败
执行日期:20151114210256
告诉我们responseTxt是正确滴,但是验证签名失败,蛋疼的一个错误,于是开始网上大江南北的找支付宝验证签名失败的各个问题,打开ecmobile\payment\alipay\sdk\notify_url.php,发现这个”验证签名失败“来自这段代码
echo “success”; //请不要修改或删除
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
else {
//验证失败
echo “fail”;//调试用,写文本函数记录程序运行情况是否正常
//logResult(“这里写入想要调试的代码变量值,或其他运行的结果记录”);
logResult(‘验证签名失败’);
}
?>
在网上搜索的时候,有个朋友在写这个支付宝验证签名失败的问题的时候,提到一点说,在ecmobile\payment\alipay\sdk\alipay.config.php中需要修改证书的相对路径为
//商户的私钥(后缀是.pen)文件相对路径
$alipay_config[‘private_key_path’] = dirname(__FILE__) . ‘../../key/rsa_private_key.pem’;//支付宝公钥(后缀是.pen)文件相对路径
$alipay_config[‘ali_public_key_path’]= dirname(__FILE__) . ‘../../key/alipay_public_key.pem’;
默认的相对路径为”/../key/alipay_public_key.pem“,这里修改多加了两个点,但是我还是验证失败,于是我在notify_url.php的else{}中加了一个
logResult($alipay_config[‘ali_public_key_path’]);
logResult($alipay_config[‘cacert’]);
来看看这个路径到底是什么。
结果是让人有点意外,不管是”/../“还是”../../“都没有让路径返回到上一个目录,因为key是和sdk平行的一个目录,于是我将证书路径代码修改了一下,加多一个dirname函数,这样证书路径代码就变为
//商户的私钥(后缀是.pen)文件相对路径
$alipay_config[‘private_key_path’] = dirname(dirname(__FILE__)) . ‘\key\rsa_private_key.pem’;//支付宝公钥(后缀是.pen)文件相对路径
$alipay_config[‘ali_public_key_path’]= dirname(dirname(__FILE__)) . ‘\key\alipay_public_key.pem’;
再经过测试,证书路径正确了,但是签名验证错误的问题依然存在,
因为在notify_url.php开头
require_once(“alipay.config.php”);
require_once(“lib/alipay_notify.class.php”);//计算得出通知验证结果
$alipayNotify = new AlipayNotify($alipay_config);
$verify_result = $alipayNotify->verifyNotify();
是通过verifyNotify函数来判断是否通过的,于是跑到lib/alipay_notify.class.php中查看verifyNotify函数。一路追踪到\ECMobile\payment\alipay\sdk\lib\alipay_rsa.function.php中的rsaVerify函数,这个函数是决定签名验证是否通过的最直接代码。
function rsaVerify($data, $ali_public_key_path, $sign) {
$pubKey = file_get_contents($ali_public_key_path);
$res = openssl_get_publickey($pubKey);
logResult(‘rsaVerify:’.$res);
$result = (bool)openssl_verify($data, base64_decode($sign), $res);
openssl_free_key($res);
return $result;
}
代码非常简单, file_get_contents获取本地公钥证书, openssl_get_publickey大概意思是格式化相应格式吧,还特意跑去服务器看了php的openssl组件是否打开,都是正常的。最后利用php的openssl_verify函数来验证RSA加密是否一致。在《使用OpenSSL做RSA签名验证 支付宝移动快捷支付 的服务器异步通知》这篇文章中详细介绍了支付宝是怎样利用RSA这个加密来验证的。引用部分说明
RSA签名验证的过程(我们第三方企业操作)如下:接收到发送过来的字符串(如果字符串没有做url decode解码,需要做url decode解码),拆分为key、value对,按照支付宝的文档,根据key的字母升序排序,使用=和&链接,获得被签名字符串。被签名字符串做SHA1摘要算法,获得SHA1摘要字符串。如果sign_type=RSA,先将sign字段做base64解码,然后使用支付宝公钥做RSA解密,得到SHA1摘要字符串。比较两个SHA1摘要字符串,如果SHA1摘要字符串一致,则签名验证成功。
可以看到最终他是两个SHA1摘要字符串的比较,如果一致就验证成功,于是我由开始去截获 rsaVerify中的各种信息。
从结果看,都能获得准确的$data,$pubkey,$sign等数据。$pubkey数据正确,说明那个证书路径修改是正确的。这个时候基本走进了死胡同,没有什么法子可以想了,也支付测试了差不多10多次了。
有人说需要pc端的支付宝和app的支付宝一致,于是我又去修改pc的支付宝账号,可是问题依旧。后面的事实证明,pc端的ecshop支付宝账号并不需要和手机Ecshop APP ecmobile端中的支付宝账号相同,他们没有必然的相关性联系!!
当没有路走了的时候,我开始回到问题的原点想问题,我制作的alipay_public_key.pem,rsa_private_key.pem正确吗?我在ecmobile中填写的rsa_private(私钥)和rsa_alipay_public(公钥)正确吗?私钥只有一个,rsa_private_key.pem的值和rsa_private的值一样,但是公钥有rsa_private_key.pem相应的公钥rsa_public_key.pem和支付宝公钥,我尝试将rsa_alipay_public的值用两个公钥都测试了一下,问题还是依旧。于是搜索支付宝帮助,找到两篇很重要的文档。
如何生成RSA密钥:https://cshall.alipay.com/enterprise/help_detail.htm?help_id=474010
如何上传公钥:https://cshall.alipay.com/enterprise/help_detail.htm?help_id=473890
通过这两篇文档确认制作的rsa_private_key.pem,rsa_public_key.pem是没有问题的,那到底是哪里出现了问题呢,我突然想理清商户和支付宝公钥、私钥的关系。看着alipay_public_key.pem,rsa_public_key.pem,在这里我才猛然想起来,当初的一个错误,当时我制作好了这两个文件之后就直接传到服务器去了,然后将rsa_public_key.pem改名为alipay_public_key.pem,现在看来这是当时一个想当然的结果。
既然是这样,那么修正alipay_public_key.pem,跑去支付宝后台复制出支付宝公钥,然后制作,前三行是64的字符,后一行是24个字符,可是我复制出来的公钥最后一行竟然有26个字符,百思不得其解,一看我的整个秘钥,竟然有218个字符。
秘钥选错了?乖乖。
在这里,我得说,看到合作伙伴秘钥管理和无线产品秘钥管理的时候,针对app的情况,我选择的是后者,我使用的是无线产品秘钥!!事实证明这是我的另外一个想当然的结果,我想也是支付宝说明不够,解释不够的一个结果。复制出来合作伙伴秘钥,216个字符,比较吻合。于是想知道合作伙伴秘钥和无线产品秘钥到底有什么差别,为什么是合作伙伴秘钥,而不是无线产品秘钥,从app角度出发,无线产品秘钥应当合适才对啊,在支付宝的一篇帮助文章中找到了答案。
手机网站支付接口公钥上传:https://cshall.alipay.com/enterprise/help_detail.htm?help_id=483847
对于老的手机网站支付接口在“无线产品密钥管理(wap专用)”下面,新的手机网站支付接口在“合作伙伴密钥管理”下点击“RSA加密”后的“添加密钥/查看密钥
无线产品密钥是给老的手机网站使用,只是为了兼容老的手机网站!!!干嘛不在秘钥界面提醒一下啊,使我为了这个问题调试那么久,只想说,程序猿,真悲催!没有详细说明文档的开源程序要真真使用起来也是痛并快乐着滴。
好了,理理思路,正确的ecmobile下配置支付宝支付的详细步骤为:
第一步,需要一个公司支付宝账号,只有公司支付宝账号才能申请手机网站支付和移动支付。
第二步,有了公司支付宝之后,那么下面及需要制作商户自己的私钥和公钥,这个可以利用:支付宝钱包支付接口开发包2.0标准版(201501022),里面有相应的制作软件、命令和详细的教程。两个文件分别为rsa_private_key.pem,rsa_public_key.pem。将rsa_private_key.pem传到ecmobile\payment\alipay\key目录下。
第三步,登录支付宝,在PID和Key页面的合作伙伴密钥管理中,在”RSA加密“后面选择”添加秘钥“。将rsa_public_key.pem中的秘钥,即—–BEGIN PUBLIC KEY—–与—–END PUBLIC KEY—–之间的内容,去掉各种其他符号,然后输入,保存。之后点击后面的”查看支付宝公钥“就会有相应数据。copy出来用来输入ecmobile变量和制作alipay_public_key.pem
第四步,将上步中的支付宝公钥复制出来,制作alipay_public_key.pem,216个字符,按照前三行64字符,最后一行24字符排列,加上—–BEGIN PUBLIC KEY—–与—–END PUBLIC KEY—–表示,之后上传到ecmobile\payment\alipay\key目录下
第五步,在ecmobile中填写相关数据。在EcmobileManager.java的
// 获取支付宝rsa_alipay_public(公钥)
public static String getRsaAlipayPublic(Context context)
{
return “xxx”;
}
后面的XXXX替换为上面第三步获得的支付宝公钥。将第二步获得的rsa_private_key.pem中的数据,去除—–BEGIN RSA PRIVATE KEY—–和—–END RSA PRIVATE KEY—–等标识符,去掉换行符等等,排列成一行数据,
// 获取支付宝rsa_private(私钥)
public static String getRsaPrivate(Context context)
{
return “xxx”;
}
替换掉上面的xxx。
这样整个ecmobile的整个支付宝配置就完成了。希望朋友们能从中获得一些帮助。
转载请注明:百蔬君 » 【原创文章】Ecmobile修改进阶篇二-调试解决ecmobile支付宝付款之后后台任然显示未付款的问题及分析支付宝验证签名失败的原因