Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AppPayRequest签名错误,丢失了partnerid和prepareid #119

Closed
jasonhu opened this issue Jun 22, 2017 · 6 comments
Closed

AppPayRequest签名错误,丢失了partnerid和prepareid #119

jasonhu opened this issue Jun 22, 2017 · 6 comments

Comments

@jasonhu
Copy link

jasonhu commented Jun 22, 2017

由于在PayRequest的定义中,这2个属性不参与JSON的序列化,而在签名生成MAP的时候,是先转JSON对象,再转MAP,导致两个属性丢失。

而在微信APP支付的协议中,这2个数据是需要的。参考:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2

以下是PayRequest的问题代码:

	/**
	 * 冗余字段
	 */
	@XmlTransient
	@JSONField(serialize = false)
	private String prepayId;
	/**
	 * 冗余字段
	 */
	@XmlTransient
	@JSONField(serialize = false)
	private String partnerId;
@foxinmy
Copy link
Owner

foxinmy commented Jun 22, 2017

感谢关注。

请关注· com.foxinmy.weixin4j.payment.mch.APPPayRequest·类中的toRequestString方法:

public String toRequestString() {
		PayRequest payRequest = toRequestObject();
		StringBuilder content = new StringBuilder();
		content.append("<xml>");
		content.append(String.format("<appid><![CDATA[%s]]></appid>",
				payRequest.getAppId()));
		content.append(String.format("<partnerid><![CDATA[%s]]></partnerid>",
				getPaymentAccount().getPartnerId()));
		content.append(String.format("<prepayid><![CDATA[%s]]></prepayid>",
				payRequest.getPrepayId()));
		content.append(String.format("<package><![CDATA[%s]]></package>",
				payRequest.getPackageInfo()));
		content.append(String.format("<noncestr><![CDATA[%s]]></noncestr>",
				payRequest.getNonceStr()));
		content.append(String.format("<timestamp><![CDATA[%s]]></timestamp>",
				payRequest.getTimeStamp()));
		content.append(String.format("<sign><![CDATA[%s]]></sign>",
				payRequest.getPaySign()));
		content.append("</xml>");
		return content.toString();
	}

调用接口是MchPayRequest com.foxinmy.weixin4j.payment.WeixinPayProxy.createAppPayRequest(String body, String outTradeNo, double totalFee, String notifyUrl, String createIp, String attach) throws WeixinException

@jasonhu
Copy link
Author

jasonhu commented Jun 22, 2017

我是获取的toRequestObject对象,然后自己封装为json的返回,前端定义的是json格式。

签名是在toRequestObject的时候发生的。

	@Override
	public PayRequest toRequestObject() {
		PayRequest payRequest = new PayRequest(getPaymentAccount().getId(),
				"Sign=WXPay");
		payRequest.setPartnerId(getPaymentAccount().getMchId());
		payRequest.setPrepayId(getPrePayId());
		String sign = DigestUtil.MD5(
				String.format("%s&key=%s",
						MapUtil.toJoinString(payRequest, false, true),
						getPaymentAccount().getPaySignKey())).toUpperCase();
		payRequest.setPaySign(sign);
		payRequest.setSignType(SignType.MD5);
		return payRequest;
	}

@foxinmy
Copy link
Owner

foxinmy commented Jun 22, 2017

原来是这样。

一般来说支付签名的字段不会包含prepayId和partnerId,
对于prepayId在package里面就包含有了,
对于partnerId应该就是appId,
不过既然有这样的场景,我想我要修改代码了,
改toRequestObject的实现为Map,不用payRequest去签名了。

这周内,我发个新版本。
感谢反馈。

@foxinmy
Copy link
Owner

foxinmy commented Jun 22, 2017

改正的代码如下:

 PayRequest payRequest = new PayRequest(getPaymentAccount().getId(), "Sign=WXPay");
        payRequest.setPartnerId(getPaymentAccount().getMchId());
        payRequest.setPrepayId(getPrePayId());
        Map<String, String> map = new HashMap<String, String>();
        map.put("appid", getPaymentAccount().getId());
        map.put("partnerid", getPaymentAccount().getMchId());
        map.put("prepayid", getPrePayId());
        map.put("package", payRequest.getPackageInfo());
        map.put("timestamp", payRequest.getTimeStamp());
        map.put("noncestr", payRequest.getNonceStr());
        String sign = DigestUtil.MD5(
                String.format("%s&key=%s", MapUtil.toJoinString(map, false, true), getPaymentAccount().getPaySignKey()))
                .toUpperCase();
        payRequest.setPaySign(sign);
        payRequest.setSignType(SignType.MD5);
        return payRequest;

@jasonhu
Copy link
Author

jasonhu commented Jun 22, 2017

看到了,非常感谢。

你的解决方案和我的一样,我只是在外部包装了一下,重新签名再返回给终端。
代码如下:

    private Map<String, String> convertPayRequestToMap(PayRequest payRequest, String signKey) {
        Map<String, String> map = new HashMap<>();
        map.put("appId", payRequest.getAppId());
        map.put("timeStamp", payRequest.getTimeStamp());
        map.put("nonceStr", payRequest.getNonceStr());
//        map.put("paySign", payRequest.getPaySign());
//        map.put("signType", payRequest.getSignType());
        map.put("package", payRequest.getPackageInfo());
        map.put("partnerId", payRequest.getPartnerId());
        map.put("prepayId", payRequest.getPrepayId());
        // 由于APPPay的bug,需要重新签名
        String sign = DigestUtil.MD5(
                String.format("%s&key=%s",
                        MapUtil.toJoinString(map, false, true),
                        signKey)).toUpperCase();
        map.put("sign", sign);
        return map;
    }

PS:新版本推送后,回复下。另外,readme上最好标注下最新版本号:-)

这个类库开发的很好用,是用过最赞的了:)

@foxinmy
Copy link
Owner

foxinmy commented Jun 23, 2017

嗨,最新版(1.7.7)已发布到maven库,请使用。:)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants