微信支付签名后台(APP支付)错误

根据微信官网提供的SDK创建微信配置类:

public class WxConfig extends WXPayConfig {

    private byte[] certData;
    private IWXPayDomain iwxPayDomain;

    public WxConfig() throws Exception {
        // pay/apiclient_cert.p12商户密钥证书在classpath:下的地址
        ClassPathResource resource = new ClassPathResource("pay/apiclient_cert.p12");
        InputStream certStream = resource.getInputStream();
        //使用commonio工具类提供的IO流转为字节数组的方法
        certData = IOUtils.toByteArray(certStream);
        certStream.read(this.certData);
        certStream.close();
    }
    //微信开放平台APPID
    public String getAppID() {
        return "xx";
    }
    // 微信商户ID
    public String getMchID() {
        return "xx";
    }
    //微信商户密钥
    public String getKey() {
        return "xx";
    }
    public InputStream getCertStream() {
        ByteArrayInputStream certBis = new ByteArrayInputStream(this.certData);
        return certBis;
    }
    public int getHttpConnectTimeoutMs() {
        return 8000;
    }
    public int getHttpReadTimeoutMs() {
        return 10000;
    }
    public IWXPayDomain getWXPayDomain() {
        return iwxPayDomain;
    }
    public void setIwxPayDomain(IWXPayDomain iwxPayDomain) {
        this.iwxPayDomain = iwxPayDomain;
    }
}

public class WXPayDomain implements IWXPayDomain {

    private String domain = WXPayConstants.DOMAIN_API;

    private boolean primaryDomain = true;

    public void report(String domain, long elapsedTimeMillis, Exception ex) {
        this.domain = domain;
    }

    public DomainInfo getDomain(WXPayConfig config) {
        DomainInfo domainInfo = new DomainInfo(domain,primaryDomain);
        return domainInfo;
    }

    public boolean isPrimaryDomain() {
        return primaryDomain;
    }

    public void setPrimaryDomain(boolean primaryDomain) {
        this.primaryDomain = primaryDomain;
    }
}

APP下单生成预支付id,返回Android和IOS端微信支付参数

wxpay.unifiedOrder(data);
统一下单接口会根据 WXPay的 signType字段选择加密方式,
WXPay wxpay = new WXPay(config);构造函数,其中useSandbox默认为false

    if (useSandbox) {
            this.signType = SignType.MD5; // 沙箱环境
        }
        else {
            this.signType = SignType.HMACSHA256;
    }

所以new WXPay(config);此构造函数unifiedOrder方法使用的加密方式是SignType.HMACSHA256;
微信预下单,微信支付参数,微信回调,需要保持加密方法一致,所以给Android和IOS参数是加密方法应该用

public static String generateSignature(final Map<String, String> data, String key, SignType signType);
//其中signType= SignType.HMACSHA256.
public static String generateSignature(final Map<String, String> data, String key) throws Exception ;
//该方法用的加密方式默认为MD5使用此方法,需要使用WXPay的其他构造函数使   
 //this.signType = SignType.MD5;
 private ResponseBean<Map<String,String>> toWxPay(PayVo payVo) throws Exception {
        WxConfig config = new WxConfig();
        WXPayDomain myIWXPayDomain = new WXPayDomain();
        config.setIwxPayDomain(myIWXPayDomain);
        myIWXPayDomain.setPrimaryDomain(true);
        WXPay wxpay = new WXPay(config);

        IPayOrderService iPayOrderService = payOrderServiceMap.get(ORDERMAPSERVICE.get(payVo.getOrderType()));
        ResponseBean<Map<String, String>> wxPayMap = iPayOrderService.createWxPayMap(payVo.getOrderId());
        if (wxPayMap.getCode() != Constant.RESP_APP_CODE_SUCCESS) {
            return wxPayMap;
        }
        Map<String, String> data = wxPayMap.getData();

        data.put("fee_type", "CNY");
        data.put("spbill_create_ip", IPUtil.getIPAddress(httpServletRequest));
        data.put("notify_url", HttpRequestUtil.getURLRemoveServletPath(httpServletRequest)+"/pay/wxpaynotify");
        data.put("trade_type", "APP");  // 此处指定为APP支付

		/**
		 * WXPay wxpay = new WXPay(config);通过该构造方法useSandbox=false
		 * 该方法会unifiedOrder方法生成预订单的时候会使用HMACSHA256加密方式
		 */
        Map<String, String> resp = wxpay.unifiedOrder(data);

        if (Constant.WX_SUCCESS.equals(resp.get("return_code")) && Constant.WX_SUCCESS.equals(resp.get("result_code"))) {
            Map<String, String> resData = new HashMap<>();

            resData.put("appid",config.getAppID());
            resData.put("partnerid",config.getMchID());
            resData.put("prepayid",resp.get("prepay_id"));
            /**
             * package为Android端关键字所以用package1代替
             */
            resData.put("package","Sign=WXPay");
            resData.put("noncestr",resp.get("nonce_str"));
            resData.put("timestamp", DateUtil.getTimeStamp());
            /**
             * 正式环境下单默认为HMACSHA256
             * 通过generateSignature
             */
            String sign = WXPayUtil.generateSignature(resData, config.getKey(), WXPayConstants.SignType.HMACSHA256);
            resData.put("sign",sign);
            resData.put("package1","Sign=WXPay");

            return new ResponseBean<>().successApp(resData);
        }else {
            ResponseBean<Map<String,String>> bean = new ResponseBean<>();
            bean.setCode(-1);
            bean.setMsg(resp.get("err_code_des"));
            return bean;
        }

    }

验签接口

验签时加密方法要和生成微信prepayid和微信支付参数加密算法一致

    public static boolean isSignatureValid(Map<String, String> data, String key) 默认使用MD5
    public static boolean isSignatureValid(Map<String, String> data, String key, SignType signType)可以选填:
    public enum SignType {
        MD5, HMACSHA256
    }
根据前边的接口可以确定需要验签时需要使用第二种方法并且入参signType=HMACSHA256
 /**
     * 微信统一支付回调
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping("/wxpaynotify")
    public void wxpaynotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        log.debug("===============微信APP支付===============");
        String result = "FAIL";
        String msg = "";
        String xml = HttpRequestUtil.readXmlFromRequest(request);
        log.info("===============微信回调xml数据===============\n{}", xml);
        try {
            Map<String, String> wxnotify = WXPayUtil.xmlToMap(xml.toString());
            WxConfig config = new WxConfig();
            /**
             * 下单,订单,验签 加密方式统一使用HMACSHA256
             */
            boolean signatureValid = WXPayUtil.isSignatureValid(wxnotify, config.getKey(), WXPayConstants.SignType.HMACSHA256);
            if (signatureValid && "SUCCESS".equalsIgnoreCase(wxnotify.get("return_code"))) {
                boolean pay = payService.dosuccessPay(wxnotify, Constant.PAY_WX);
                if (pay) {
                    result = "SUCCESS";
                    msg = "OK";
                } else {
                    msg = wxnotify.get("return_msg");
                }
            }
        } catch (Exception e) {
            log.error("微信解析认证失败:{}", e.getMessage());
        }
        response.setHeader("Content-Type", "text/html");
        response.getWriter().write("<xml><return_code><![CDATA[" + result + "]]></return_code><return_msg><![CDATA[" + msg + "]]></return_msg></xml>");
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值