微信支付
小智
微信支付协助服务端整了2天,终于可以使用了。
我们忽略掉低级错误(服务端传过来的 随机字符串,时间戳出现的问题,)。
继承,支付成功后没有回调正确的Activity(http://fangjie.info/?p=393)
签名问题,这一块是比较严重的,服务端需要2次签名。
第一次签名:代码
List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));//appid
packageParams.add(new BasicNameValuePair("body", "weixin")); //body
packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID)); //商务号
packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));//随机字符串
packageParams.add(new BasicNameValuePair("notify_url", "http://121.40.35.3/test"));//响应url
packageParams.add(new BasicNameValuePair("out_trade_no",genOutTradNo())); //商务系统生产的订单号
packageParams.add(new BasicNameValuePair("spbill_create_ip","127.0.0.1"));//系统ip
packageParams.add(new BasicNameValuePair("total_fee", "1"));//价钱单位
packageParams.add(new BasicNameValuePair("trade_type", "APP"));//固定值
签名发送的拼串应该一致。(服务端:我们在操作的时候参数出现问题,并且还认为只进行一次签名,不需要再次进行签名,导致签名错误。Android前端:第一次签名android端不需要做签名 但是自己也做了一次签名导致了订单重复。)
第二次签名代码
private void genPayReq() {
req.appId = APP_ID;//公众号id
req.partnerId = mMch_id;//商务号id
req.prepayId = mPrepay_id;//微信返回的支付交易会话ID
req.packageValue = "Sign=WXPay";//固定值
req.nonceStr = genNonceStr();//随机字符串
req.timeStamp = mTimestamp;//时间戳
//判断前端 与服务端签名是否一致
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", req.appId));
signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
signParams.add(new BasicNameValuePair("package", req.packageValue));
signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
//判断前后端签名是否一致
if (!mSign.equals(genAppSign(signParams))) {
Toast.makeText(ConfirmOrderFragmentActivity.this, "前后端签名不一致", Toast.LENGTH_SHORT).show();
return;
}
req.sign = mSign;
Log.e("orion", signParams.toString());
}
在genAppSign(signParams)再次进行了一次签名参数与字段服务端必须保持一致(服务端:发现错误后做第二次签名,但是又遇到问题:参数字段不对,和随机字符串,时间戳参数没有跟第一次签名保持一致。android端:删掉请求第一次签名的代码。)
经过反复的整理思路,把签名搞通了,最后Android端做一次安全性判断,使用服务端给到的参数进行第二次签名然后将签名结果与服务端的签名结果做比较
(做安全验证的原因在后面做解释)。如果匹配成功回调支付页面。
//发送微信支付请求
private void sendPayReq() {
msgApi.registerApp(APP_ID);
msgApi.sendReq(req);
}
为什么支付不成功返回-1
当我们sendReq(req)的时候,他会与微信端生成的签名进行匹配,如果匹配不成功会出现-1签名错误,这个时候只要流程是通的,仔细检测参数即可。
支付成功后,微信没有回调服务端。
原因如下,这里必须用https 并且不能带有参数。(注意一点:签名要大写,随机字符串不一定要大写)
最后将notify_url改成https。开始回调了。
再做一下测试,又不能回调了。
分析原因:1,微信回调延迟。
2,响应url有问题。
(ok最后结果是服务端url写错了。)
3.安全遗漏
以上的代码可以看到,我这边也再做了一次签名,这个签名是怎么回事:(我们ios出现了这个问题)
分析:
当我们发送签名的时候,随机字符串与服务端的随机字符串不一致的情况,例如:android前端使用的随机字符串是自己生成的,与服务端的也是自己生成的,生成方式不一致导致随机字符串不一致,但是仍然可以付款成功并回调页面
(检测签名是在微信端的在微信端检测签名格式正确,就不会去校验第二次签名的参数了。)
重点就在于检测格式,而没有检测签名参数。是否一致。所以当我们前后台的签名不一致也通过了支付流程 回调到了页面。所以我们需要在前端进行以下改进。使用服务端的参数在前端进行第二次签名的流程,与在服务端拿到的签名进行对比验证。
//判断前端 与服务端签名是否一致
List<NameValuePair> signParams = new LinkedList<NameValuePair>();
signParams.add(new BasicNameValuePair("appid", req.appId));
signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
signParams.add(new BasicNameValuePair("package", req.packageValue));
signParams.add(new BasicNameValuePair("partnerid", req.partnerId));
signParams.add(new BasicNameValuePair("prepayid", req.prepayId));
signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
//判断前后端签名是否一致
if (!mSign.equals(genAppSign(signParams))) {
Toast.makeText(ConfirmOrderFragmentActivity.this, "前后端签名不一致", Toast.LENGTH_SHORT).show();
return;
}
req.sign = mSign;
微信支付这个时候才真正完成完成
后续问题:
出现签名错误
当我们检测签名,appid,包名都没有问题的时候,清一下缓存就可以解决了。
预测原因:之前的签名被缓存了。(暂未证实)