我的操作流程
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.错误截图
第一次发帖排版不好大家见谅,望各位大佬
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();
我生成了 前端请求报错误 请问是怎么解决的 找一天多了 全是v2和v3混合的 乱七八糟的
已解决,paySign生成签名拼的参数与请求头的不同
paySign和统一下单的签名是同一个函数;
我只有node的:
function getSign(parts = [], key, str = '') { parts.forEach(v => str += v + '\n') return crypto.createSign('RSA-SHA256').update(str).sign(key, 'base64') }
参考V3签名文档https://wechatpay-api.gitbook.io/wechatpay-api-v3/