收藏
回答

微信支付API-V3 怎样获取返回前端的paySign签名

我的操作流程

1.用官方sdk发送请求获取到prepay_id,但是sdk内并没有看到获取paySign签名的方法(返回前端用于拉起微信支付)

// 读取证书私钥
PrivateKey privateKey = PemUtil.loadPrivateKey(new ClassPathResource("apiclient_key.pem").getInputStream());

// 读取平台证书(验签)
X509Certificate certificate = PemUtil.loadCertificate(
    new ClassPathResource("wechatpay_774380E742E4F04BFCFA2804DA234160D8093CE3.pem").getInputStream());
List<X509Certificate> certificates = Arrays.asList(certificate);

// 生成请求签名
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
    .withMerchant(WxConstants.PAY_MCH_ID, WxConstants.PAY_SERIAL_NO, privateKey).withWechatpay(certificates);

2.生成paySign签名的方法(下段代码)

public static String getSign(String nonceStr, long timestamp, String body, String serialPath) {
    // 请求路径
    HttpUrl url = HttpUrl.parse("https://api.mch.weixin.qq.com/v3/certificates");
    // 组装需要签名的数据
    String message = buildMessage("GET", url, timestamp, nonceStr, body);
    // 使用私钥对数据进行签名(加密),【数据签名之后需要转换为字节数组(采用utf-8)】
    String signature = null;
    try {
        signature = sign(message.getBytes("utf-8"), serialPath);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return signature;
}

private static String sign(byte[] message, String serialPath) {
    try {
        // 签名方式(固定SHA256withRSA)
        Signature sign = Signature.getInstance("SHA256withRSA");
        // 使用私钥进行初始化签名(私钥需要从私钥文件【证书】中读取)
        sign.initSign(getPrivateKey(serialPath));
        // 签名更新
        sign.update(message);
        // 对签名结果进行Base64编码
        return Base64.getEncoder().encodeToString(sign.sign());
    } catch (SignatureException | InvalidKeyException | NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return null;
}

private static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
    String canonicalUrl = url.encodedPath();
    if (url.encodedQuery() != null) {
        canonicalUrl += "?" + url.encodedQuery();
    }
    return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
}

3.其中body参数传入空串或返还前端JSONObject的json串都有试过,都是在调起微信支付时弹窗提示支付验证签名失败

// 返回前端数据
JSONObject payMap = new JSONObject();
payMap.put("appId", WxConstants.OFFICIAL_APPID);
long timestamp = System.currentTimeMillis() / 1000;
payMap.put("timeStamp", timestamp + "");
String nonceStr = WXPayUtil.generateNonceStr();
payMap.put("nonceStr", nonceStr);
payMap.put("package", "prepay_id=" + prepay_id);
payMap.put("signType", "RSA");

// 生成请求签名
String jsonStr = new JSONObject(payMap).toJSONString();
String paySign = WxV3Authorization.getSign(nonceStr, timestamp, jsonStr, "apiclient_key.pem");
System.out.println("paySign:" + paySign);
payMap.put("paySign", paySign);

4.生成签名样例

paySign:u/QxdeRo0+nalos8j+phrLLFCiygdXHa7RuushwG0QzgodrG+nfLKFoLDK77ojkNzdtB7yqySHriig90qjcZ8XhSOYAQ6WMRPWBhtJ+XgLJgrSk6kvDVXZ0YaDVa12jfruggYdK2lCaimuY0L6mxMdiwhxqWDIkyZadmh0N/nDPN/k+6Mjj8k2G6Gy6k0Nnlu+zldDclUwxPoKwNLYRUfTxZUho/8CQq/BlTIhDR+aGueZGu/dzfDOpxLHthTc3M00LNQtv4O7iT50Hgunqkug7ltS1Y63IUj+n/zMvDKTq3SONMo8XOilZrreRjXi4JbuLGWYIVR0XADz3+dik4mw==

5.错误截图

第一次发帖排版不好大家见谅,望各位大佬

回答关注问题邀请回答
收藏

5 个回答

  • E*Memory
    E*Memory
    03-05

    java后端我用以下方法成功了,真是汗颜,官方也没有直接提供一下这样的函数给人用:

    <dependency>
       <groupId>com.github.wechatpay-apiv3</groupId>
       <artifactId>wechatpay-java</artifactId>
       <version>0.2.12</version>
    </dependency>
    ----
    
    // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
    Config config = null;
    
    ----
     if (config == null) {
                    config = new RSAAutoCertificateConfig.Builder()
                            .merchantId(MCH_ID)
                            .privateKeyFromPath(privateKeyPathWeiXin)
                            .merchantSerialNumber(merchantSerialNumber)
                            .apiV3Key(apiV3Key)
                            .build();
                }
                JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
    
    // 跟之前下单示例一样,填充预下单参数
                PrepayRequest request = new PrepayRequest();
    
                Amount amount = new Amount();
                amount.setTotal(Integer.parseInt(amountStr));
                request.setAmount(amount);
    
                request.setAppid(wxminiAppid);
                request.setMchid(MCH_ID);
                request.setDescription(subject);
                request.setNotifyUrl(NOTIFY_URL);
                request.setOutTradeNo(outTradeNo);
    
                request.setAttach(passbackParams);
                Payer payer1 = new Payer();
                payer1.setOpenid(openid);
                request.setPayer(payer1);
    
    // response包含了调起支付所需的所有参数,可直接用于前端调起支付
                PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
                String packageVal = response.getPackageVal();
                System.out.println(packageVal);
    
    -----
    
      String packageStr = packageVal;
                String signType = "RSA";
                String tosingStr = wxminiAppid + "\n" + timeStamp + "\n" + nonceStr + "\n" + packageStr + "\n";
    
                Signer signer = config.createSigner();
                String paySign = signer.sign(tosingStr).getSign();
    
    //            paySign = signWithRSA2(tosingStr, PROVIDER);
                System.out.println("paySign=" + paySign);
                jsonObjectRes.put("timeStamp", timeStamp);
                jsonObjectRes.put("nonceStr", nonceStr);
                jsonObjectRes.put("package", packageStr);
                jsonObjectRes.put("signType", signType);
                jsonObjectRes.put("paySign", paySign);
    return jsonObjectRes;
    


    其中就是直接用它sdk里的加密方法:  Signer signer = config.createSigner();
                String paySign = signer.sign(tosingStr).getSign();
    


    03-05
    有用
    回复
  • 小晏同学
    小晏同学
    2022-01-12

    我生成了 前端请求报错误 请问是怎么解决的 找一天多了 全是v2和v3混合的 乱七八糟的

    2022-01-12
    有用
    回复
  • 星火
    星火
    2020-10-28

    已解决,paySign生成签名拼的参数与请求头的不同

    2020-10-28
    有用
    回复 7
    • May
      May
      2020-12-28
      可以提供下paysign生成的代码吗
      2020-12-28
      回复
    • 无为
      无为
      2021-01-05
      同求,一模一样的错误
      2021-01-05
      回复
    • 徐先森
      徐先森
      2021-01-08
      同求 ,java代码,我这个问题已经烦恼了好几天了
      2021-01-08
      回复
    • 楊
      2021-02-02回复徐先森
      你好,请问你的解决了么
      2021-02-02
      回复
    • 小晏同学
      小晏同学
      2022-01-12回复徐先森
      找到了吗
      2022-01-12
      回复
    查看更多(2)
  • 老张
    老张
    2020-10-27

    paySign和统一下单的签名是同一个函数;

    我只有node的:

    function getSign(parts = [], key, str = '') {
      parts.forEach(v => str += v + '\n')
      return crypto.createSign('RSA-SHA256').update(str).sign(key, 'base64')
    }
    
    2020-10-27
    有用
    回复 1
    • 星火
      星火
      2020-10-27
      hhh蟹蟹啦,我想要java后端的
      2020-10-27
      回复
  • 微信支付技术助手8
    微信支付技术助手8
    2020-10-27

    参考V3签名文档https://wechatpay-api.gitbook.io/wechatpay-api-v3/


    2020-10-27
    有用
    回复 1
    • 星火
      星火
      2020-10-27
      您好,我就是看文档用的文档的签名生成方法鸭(但是文档是生成整个认证请求头的,我把拼参数部分去了直接返回signature值),是哪里操作的不对吗,传过去的body文档上说要空串,那怎么根据prepay_id及apikeyV3的秘钥生成paySign鸭,看文档生成签名的方法没有地方传这俩参数进去
      2020-10-27
      回复
登录 后发表内容
问题标签