最近研究微信支付,尝试用jsapi前端发起支付时,弹出“支付签名验证失败”,多方查找后发现是由于统一下单时的加密方式与前端再次签名时的签名方式不同导致。
官方的SDK中WXPay类的构造函数定义是这样的:
public WXPay(final WXPayConfig config) throws Exception {
this(config, null, true, false); //useSandbox值为false,即默认为非沙箱环境
}
...//此处省略
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; //非沙箱环境signtype默认为HMACSHA256
}
this.wxPayRequest = new WXPayRequest(config);
}
所以在使用官方的示例时:
MyConfig config = new MyConfig();
WXPay wxpay = new WXPay(config);
默认signtype值为SignType.HMACSHA256而不是SignType.MD5。
那么如果直接给定sign_type值为MD5是不是就可以了呢?通过研究后续代码发现:在WXPay.fillRequestData方法中压根儿就没有判断用户是否传入了默认的sign_type,所以给了默认值也没用。
public Map fillRequestData(Map reqData) throws Exception {
reqData.put("appid", config.getAppID());
reqData.put("mch_id", config.getMchID());
reqData.put("nonce_str", WXPayUtil.generateNonceStr());
if (SignType.MD5.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.MD5);
}
else if (SignType.HMACSHA256.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.HMACSHA256);
}
reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
return reqData;
}
这里可以将上面这个方法更改一下,判断一下初始给定的默认值就OK了。(PS:也可以根据需求按照指定的构造方法初始化WXPay实例。)
public Map fillRequestData(Map reqData) throws Exception {
reqData.put("appid", config.getAppID());
reqData.put("mch_id", config.getMchID());
reqData.put("nonce_str", WXPayUtil.generateNonceStr());
String userSignType = ""+reqData.get("sign_type"); //如果定义了signtype,则使用定义的signtype
if(userSignType.equals(WXPayConstants.MD5)){
this.signType = SignType.MD5;
}else if(userSignType.equals(WXPayConstants.HMACSHA256)){
this.signType = SignType.HMACSHA256;
}else{
if (SignType.MD5.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.MD5);
}
else if (SignType.HMACSHA256.equals(this.signType)) {
reqData.put("sign_type", WXPayConstants.HMACSHA256);
}
}
reqData.put("sign", WXPayUtil.generateSignature(reqData, config.getKey(), this.signType));
return reqData;
}
另外,还需注意官方文档中的描述:参数区分大小写以及签名方式与统一下单时的签名类型一致!