评论

记录App支付遇到的坑,全面解析

微信支付签名失败(2次签名)

最近公司有个项目,包括App、公众号、pc端、小程序,都涉及到了微信、支付宝支付,在此过程中花了两天时间把踩到的坑记录在此,便于后来人少走弯路。

目前只把微信支付接完了,后续会持续更新其他几端遇到的坑以及解决方案。我用的是 netcore3.1

1:App支付

第一次签名(统一支付,获取预支付id)

注意点

所有必填参数一定要按照文档实例的顺序来,下方为我的参数,一定要注意下方的参数顺序

appid、attach、body(可选)、mch_id、nonce_str、notify_url、out_trade_no、spbill_create_ip、total_fee、trade_type、sign_typeca

参数取值:

appid取值:登录open.weixin.qq.com查看,注意与公众号的APPID不同

mch_id取值:https://pay.weixin.qq.com/index.php/extend/employee 进入后,点击左侧的[商户信息],会看到基本账户信息,下方有一个[微信支付商户号],这一步有很多大兄弟取错值。

nonce_str取值:直接使用官方提供的方法即可。

notify_url取值:通知url必须为直接可访问的url,不能携带参数。

out_trade_no、spbill_create_ip取值:问题不大。

total_fee取值:单位为,一定要注意传入的参数要转化为分

trade_type取值:默认值为APP,因为我的接入方是App,所以此处是固定值,一定要注意大小写 是 APP 不是 App 或 app

sign_type取值:文档其实写的很清楚,这个字段为非必填,一旦你不传,默认的加密方式为MD5,但是我从官网下的demo看到里面默认的是HMAC-SHA256,找了2小时才发下这个问题,重点来了:建议sign_type传值为MD5方式,为什么呢?因为在调起App支付页之前还需要二次签名,如果用HMAC-SHA256加密 那边可能会有问题,下面在细说。

sign取值:对上述的参数进行 MD5 HMAC-SHA256时,sign不参与签名。

在保证以上参数取值没问题的情况下,来说下加密的问题,下方是从测试工具截图,做一下解释

测试工具地址 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=20_1



红框里面的注意事项解释下:当前商户KEY是否正确,这个KEY的取值地址如下

https://pay.weixin.qq.com/index.php/extend/employee 进入后 点击上方的[账户中心]进入,然后在左侧有个【API安全】,进入后,注意!!找到【API密钥】,不是PAIv3!!!,重置下API密钥,这里有个生效时间15分钟,网上很多帖子说签名失败时,多次重置这个密钥就好了,我没有遇到,保证上面的参数正确就通过了。

网上很多签名失败的解决方案,本人也看了很多,基本上没用得上,比如ip黑白名单,我在本地都跑起来了,也没配置黑白名单啥的。

以下是完整的第一次签名:

inputObj.SetValue("appid", AppId);//APPID
inputObj.SetValue("attach", order_body);//附加数据 可选
inputObj.SetValue("body", order_body);//订单body
inputObj.SetValue("mch_id", Mch_id);//商户号
inputObj.SetValue("nonce_str", RandomGeneratHepler.GenerateNonceStr());//随机字符串
inputObj.SetValue("notify_url", Notfy_url);//回调地址
inputObj.SetValue("out_trade_no", order_code);//订单号
inputObj.SetValue("spbill_create_ip", Spbill_ip);//终端ip
inputObj.SetValue("total_fee", total_amount);//	订单总金额 测试时,金额不能是0.01     
inputObj.SetValue("trade_type", "APP");//支付方式
//inputObj.SetValue("sign_type", "HMAC-SHA256");//签名类型 可选 不选默认为MD5加密
inputObj.SetValue("sign", inputObj.MakeSign().ToUpper()); //签名加密
string xml = inputObj.ToXml();
string response = HttpService.Post(xml, Unifiedorder_url, false, timeOut);

总结下:

1:参数顺序和参数个数是否一致,包括大小写、下划线等

2:各个参数的取值问题,比如商户号、加密的key等

3:一定要有耐心!!!不要急躁,急躁解决不了任何问题,反而弄的自己没状态没心思仔细看文档。

以上是第一次签名(大概花了一下午),签名成功后会返回以下几个参数,具体如下:

mch_id(商户号)、nonce_str(随机数)、appid、prepay_id(预支付id)、sign等,这些参数在App调起微信支付时进行二次签名。

第二次签名,App端调起微信支付页

由后端进行二次签名后,传给App端,App端拿到参数后发起调起。

二次签名参数:

appid、partnerid(商户号)、prepayid(预支付id)、noncestr(随机数)、timestamp、package

注意点:

(1)此次签名要与第一次签名完全一致,这块容易出错的地方为:如果在第一次签名时,加入sign_type,那么此处也要加入,且加密方式要与第一次加密一致。上面说到为什么要用MD5加密,是因为在我们使用HMAC-SHA256加密时,你在测试工具验证通过了,然后app端调起时一直报签名失败,明明测试工具都通过了呀,这是为啥呢?那是因为,客户端的skd版本不同,对应的加密方式默认为了MD5!!!所以,在第二次加密用HMAC-SHA256时,得到的参数返回给客户端时,一直提示签名错误!!(本人在这边卡了2个小时,很郁闷)。

(2)另外在android端调起时,如果发下ios调起了,android没调起,问题可能出现在微信的缓存中,建议用另外一台手机测试,或者把微信卸载后在安装试一下,这个问题是刚才android反馈的,可能是微信的缓存导致的。

(3)第二次签名相对于第一次要简单些,网上很多例子有误导的,比如下图标红的地方,如果你按照这个参数去签名的话,恭喜你,100%不成功!因为下方的

参数有大写的!!!,你说坑不坑?

(4)参数顺序建议按照下方实例来,我没有侧过第二次签名参数顺序不一致是否会导致签名失败。

完整的二次签名参数如下:

 inputObj.SetValue("appid", entity.appid);//APPID
 inputObj.SetValue("partnerid", Mch_id);//商户号
 inputObj.SetValue("prepayid", entity.prepay_id);//预支付id
 inputObj.SetValue("noncestr", entity.nonce_str);//随机数
 inputObj.SetValue("timestamp", timeStamp);//时间戳
 inputObj.SetValue("package", entity.package);//扩展字段 固定值为 Sign=WXPay
  //inputObj.SetValue("sign_type", "HMAC-SHA256");//签名类型 可选 不选默认为MD5加密
  inputObj.SetValue("sign", inputObj.MakeSign().ToUpper());//调用签名方法,返回后需转为大写

entity为调统一支付接口返回的内容,注意这里面有个timestamp,这个是10位数的时间戳,我的取值如下

var currentDte = DateTime.Now;
DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0);
int timeStamp = Convert.ToInt32((currentDte - dateStart).TotalSeconds);

另外 下方为两次签名的方法,供参考

        /**
        * @生成签名,详见签名生成算法 
        * @return 签名, sign字段不参加签名
        */
        public string MakeSign(string signType)
        {
            var Api_key = Appsettings.app("WechatPay", "Pay", "Api_key");//此处的key就是上面说的API密钥,获取途径见上方说明
            string str = ToUrl();//转url格式     
            str += "&key=" + Api_key; //在string后加入API KEY
            if (signType == SIGN_TYPE_MD5)
            {
                var md5 = MD5.Create();
                var bs = md5.ComputeHash(Encoding.UTF8.GetBytes(str));
                var sb = new StringBuilder();
                foreach (byte b in bs)
                {
                    sb.Append(b.ToString("x2"));
                }
                return sb.ToString().ToUpper();//所有字符转为大写
            }
            else if (signType == SIGN_TYPE_HMAC_SHA256)
            {
                return CalcHMACSHA256Hash(str, Api_key);// WechatPayConfig.GetConfig().GetKey());
            }
            else
            {
                throw new WxPayException("sign_type 不合法");
            }
        }


        /**
        * @生成签名,详见签名生成算法
        * @return 签名, sign字段不参加签名 SHA256
        */
        public string MakeSign()
        {
            return MakeSign(SIGN_TYPE_MD5);//全部默认MD5加密  因为客户端sdk版本不同 加密方式默认的是MD5
        }

最后唠叨几句,多点耐心,别急躁,自行看文档,祝君好运,希望对各位大兄弟有所帮助。本文是在中午吃饭的时候总结的,排版有点乱,望见谅。
如大家在对接支付遇到其他问题,也可以在下方留言,顺便告知如何解决的,为他人做些贡献。
最后一次编辑于  2020-03-13  
点赞 1
收藏
评论

10 个评论

  • wangb
    wangb
    2020-10-15

    博主,您好,请问二次签名的时候,随机字符串是重新生成吗

    2020-10-15
    赞同 1
    回复 1
    • 李宇阳
      李宇阳
      2020-11-14
      我从返回报文里取的,调通了
      2020-11-14
      回复
  • N. J. Q
    N. J. Q
    2020-12-18

    努比亚调不起来,其他手机正常怎么回事,微信清缓存了

    2020-12-18
    赞同
    回复
  • 李宇阳
    李宇阳
    2020-11-14

    时间2020/11/14 感谢这位老哥

    微信官方demo 默认沙箱模式md5 正常模式是HMACSHA256

    前端默认MD5 ,两次不一样确实是这里的问题,前端换起支付签名不通过的同学注意下这里

    public WXPay(final WXPayConfig config, final String notifyUrl, final boolean autoReport, final boolean useSandbox) throws Exception {
        this.config = config;
        this.notifyUrl = notifyUrl;
        this.autoReport = autoReport;
        this.useSandbox = useSandbox;
        if (useSandbox) {
            this.signType = SignType.MD5; // 沙箱环境
        }
        else {
            this.signType = SignType.HMACSHA256;
        }
        this.wxPayRequest = new WXPayRequest(config);
    }
    
    2020-11-14
    赞同
    回复
  • 夏尔
    夏尔
    2020-10-22

    安装上面的操作, uni-app返回 requestPayment:fail errors 是什么原因

    2020-10-22
    赞同
    回复
  • 云水禅心 - 张先生
    云水禅心 - 张先生
    2020-06-07

    搏主您好,看到您的这篇文章倍感欣慰,微信支付之歌问题已经困扰了我 好久了,还好项目不急,但是时间也是太长了,我简单描述下我的问题吧,希望能改到一些解决方案。

    我后端服务器是 JavaWeb 项目,前端是 安卓java 项目,现在遇到的问题是 调用统一下单API 后成功返回数据,签名代码是网上copy修改的, 还好成功返回了SUCCESS。直接将返回的XML数据返回给安卓客户端的话 客户端报 “支付验证签名失败” !

    查看微信文档后发现有这么一句话:

    3、调起支付:

    商户服务器生成支付订单,先调用【统一下单API】生成预付单,获取到prepay_id后将参数再次签名传输给APP发起支付。

    出现了再次签名的问题,您上面也提到 要和第一次签名一致,我也试了,发现问题还是没有解决,也在网上 百度了很多资料和 代码,也没能成功,所以看看搏主这边有没有合适的第一次签名和第二次签名的标准代码,或者是 您帮忙看下我这边的签名代码 是不是还存在着问题,本人从事开发时间也不长,有很多的逻辑 苦恼无法实现,所以您把我当新手看哈,感激不尽!

    2020-06-07
    赞同
    回复
  • 张倩
    张倩
    2020-05-25

    你们是普通商户还是服务商呢? 你们的商户都是与你们主体一致的吗?

    2020-05-25
    赞同
    回复 2
  • Javen
    Javen
    2020-04-12
    Java 版本 https://gitee.com/javen205/IJPay Node.js 版本推荐 https://gitee.com/javen205/TNWX
    2020-04-12
    赞同
    回复
  • 叉叉
    叉叉
    2020-03-30

    请问下,在第三方app中,能给用户下发微信支付的代金券,或者银行的立减金么?

    2020-03-30
    赞同
    回复 2
    • Javen
      Javen
      2020-04-12
      目前不支持三方 app发券,但支持二维码的方式,长按保存吧
      2020-04-12
      回复
    • Javen
      Javen
      2020-04-12
      也有一个折中方案 支付有礼的满减 https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/paygiftactivity/chapter3_2.shtml
      2020-04-12
      回复
  • Kys
    Kys
    2020-03-19

    感谢分享,这边支付遇到了一个问题,就是能唤起起微信,并且支付成功,之后点击返回商户,没有进到WXPayEntryActivity中。我不知道是不是这个会影响到,我的application里面有大写字母,包名是纯小写的。困扰了好长时间 了

    2020-03-19
    赞同
    回复 1
    • Javen
      Javen
      2020-04-12
      Activity 要放到与包名同一目录下
      2020-04-12
      回复
  • 人生当若初见
    人生当若初见
    2020-03-13

    文章排版有点乱,大家将就看看吧,希望对您有所帮助~

    2020-03-13
    赞同
    回复
登录 后发表内容