前言
最近公司新商户号接入的时候用binarywang框架发现提示证书不存在,在网上一搜啥也没有,最后在微信开放社区得知新商户只支持公钥模式了,不支持平台证书了,导致代码里面自动更新证书的时候会提示证书不存在,找了半天也没找到解决方法,没办法只能另辟蹊径,研究一下binarywang的源码里面是怎么调用的,结合微信官方的sdk,总算是找到了适配的方法,暂时解决了这个问题。
思路
话不多说直接说思路。
我用的是binarywang的4.5.0版本(其他版本应该不影响这个方式)
排查了一下我用到的几个方法,支付、分账、退款、添加分账用户等等方法,里面敏感信息加密和身份验证什么的,最终都是从WxPayConfig这个类里面拿的,那直接重写这个类不就行了。
第一步:
报错证书不存在的是在WxPayConfig.initApiV3HttpClient这个方法里面,所以主要改这个方法就行了。
先复制这个WxPayConfig类的内容,新建一个WxPayCustomConfig类。重点:内容从WxPayConfig里面复制出来,并且继承WxPayConfig这个类,这样在配置的时候,就能设置这个类进去了。
WxPayCustomConfig类里面再加2个字段,一个publicKeyPath(公钥证书路径),一个publicKeyId(公钥证书ID)。然后改initApiV3HttpClient这个方法,这里我直接上代码吧。
WxPayCustomConfig类代码:
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.config.WxPayHttpProxy;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.util.HttpProxyUtils;
import com.github.binarywang.wxpay.util.ResourcesUtils;
import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder;
import com.github.binarywang.wxpay.v3.auth.*;
import com.github.binarywang.wxpay.v3.util.PemUtils;
import lombok.Data;
import lombok.SneakyThrows;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.ssl.SSLContexts;
import org.jeecg.modules.locker.utils.PemUtil;
import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Base64;
@Data
public class WxPayCustomConfig extends WxPayConfig {
private static final String DEFAULT_PAY_BASE_URL = "https://api.mch.weixin.qq.com";
private static final String PROBLEM_MSG = "证书文件【%s】有问题,请核实!";
private static final String NOT_FOUND_MSG = "证书文件【%s】不存在,请核实!";
private String publicKeyPath;
private String publicKeyId;
/**
* 微信支付接口请求地址域名部分.
*/
private String payBaseUrl = DEFAULT_PAY_BASE_URL;
/**
* http请求连接超时时间.
*/
private int httpConnectionTimeout = 5000;
/**
* http请求数据读取等待时间.
*/
private int httpTimeout = 10000;
/**
* 公众号appid.
*/
private String appId;
/**
* 服务商模式下的子商户公众账号ID.
*/
private String subAppId;
/**
* 商户号.
*/
private String mchId;
/**
* 商户密钥.
*/
private String mchKey;
/**
* 企业支付密钥.
*/
private String entPayKey;
/**
* 服务商模式下的子商户号.
*/
private String subMchId;
/**
* 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数.
*/
private String notifyUrl;
/**
* 交易类型.
* <pre>
* JSAPI--公众号支付
* NATIVE--原生扫码支付
* APP--app支付
* </pre>
*/
private String tradeType;
/**
* 签名方式.
* 有两种HMAC_SHA256 和MD5
*
* @see com.github.binarywang.wxpay.constant.WxPayConstants.SignType
*/
private String signType;
private SSLContext sslContext;
/**
* p12证书base64编码
*/
private String keyString;
/**
* p12证书文件的绝对路径或者以classpath:开头的类路径.
*/
private String keyPath;
/**
* apiclient_key.pem证书base64编码
*/
private String privateKeyString;
/**
* apiclient_key.pem证书文件的绝对路径或者以classpath:开头的类路径.
*/
private String privateKeyPath;
/**
* apiclient_cert.pem证书base64编码
*/
private String privateCertString;
/**
* apiclient_cert.pem证书文件的绝对路径或者以classpath:开头的类路径.
*/
private String privateCertPath;
/**
* apiclient_key.pem证书文件内容的字节数组.
*/
private byte[] privateKeyContent;
/**
* apiclient_cert.pem证书文件内容的字节数组.
*/
private byte[] privateCertContent;
/**
* apiV3 秘钥值.
*/
private String apiV3Key;
/**
* apiV3 证书序列号值
*/
private String certSerialNo;
/**
* 微信支付分serviceId
*/
private String serviceId;
/**
* 微信支付分回调地址
*/
private String payScoreNotifyUrl;
/**
* 微信支付分授权回调地址
*/
private String payScorePermissionNotifyUrl;
private CloseableHttpClient apiV3HttpClient;
/**
* 私钥信息
*/
private PrivateKey privateKey;
/**
* 证书自动更新时间差(分钟),默认一分钟
*/
private int certAutoUpdateTime = 60;
/**
* p12证书文件内容的字节数组.
*/
private byte[] keyContent;
/**
* 微信支付是否使用仿真测试环境.
* 默认不使用
*/
private boolean useSandboxEnv = false;
/**
* 是否将接口请求日志信息保存到threadLocal中.
* 默认不保存
*/
private boolean ifSaveApiData = false;
private String httpProxyHost;
private Integer httpProxyPort;
private String httpProxyUsername;
private String httpProxyPassword;
/**
* v3接口下证书检验对象,通过改对象可以获取到X509Certificate,进一步对敏感信息加密
* <a href="https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/min-gan-xin-xi-jia-mi">文档</a>
*/
private Verifier verifier;
/**
* 返回所设置的微信支付接口请求地址域名.
*
* @return 微信支付接口请求地址域名
*/
public String getPayBaseUrl() {
if (StringUtils.isEmpty(this.payBaseUrl)) {
return DEFAULT_PAY_BASE_URL;
}
return this.payBaseUrl;
}
@SneakyThrows
public Verifier getVerifier() {
if (verifier == null) {
//当改对象为null时,初始化api v3的请求头
initApiV3HttpClient();
}
return verifier;
}
/**
* 初始化ssl.
*
* @return the ssl context
* @throws WxPayException the wx pay exception
*/
public SSLContext initSSLContext() throws WxPayException {
if (StringUtils.isBlank(this.getMchId())) {
throw new WxPayException("请确保商户号mchId已设置");
}
try (InputStream inputStream = this.loadConfigInputStream(this.keyString, this.getKeyPath(),
this.keyContent, "p12证书");) {
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] partnerId2charArray