最近微信商户给老板推送了一个支付即服务的功能,老板看到了就想要,好吧,那就搞吧,看流程挺简单的
但是是微信支付V3版API文档,里面和之前V2还是有出入的,
相较于的之前微信支付API,主要区别是:
-
遵循统一的Restful的设计风格
-
使用JSON作为数据交互的格式,不再使用XML
-
使用基于非对称密钥的SHA256-RSA的数字签名算法,不再使用MD5或HMAC-SHA256
-
不再要求HTTPS客户端证书
-
使用AES-256-GCM,对回调中的关键信息进行加密保护
刚开始摸这个的时候一脸雾水,看了一天文档后,嗯,基本看懂了他的流程,流程我就不多说了,可以去看文档,写的还是比较详细的
老规矩,我就直接上码吧!
下文可能会出现的参数
String keyPath = "apiclient_key.pem";// 私钥证书
String mchId = "";
String serialNo = "";//公钥证书序列号
String body = ""; // 请求报文主体,没有查询参数。
String platformCertPath = "WXapiclient_cert.pem";//微信平台证书 验证签名时需要使用
//获取公钥证书序列号
public String getSerinlNo(){
X509Certificate certificate = PayKit.getCertificate(FileUtil.getInputStream("apiclient_cert.pem 证书路径"));
String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
}
案例一 :获取平台证书(如果所需要的API没有涉及到敏感数据,可以不调用这个API,但我们以这个为案例)
@Test
public void v3Get() {
// 获取平台证书列表
try {
Map<String, Object> result = WxPayApi.v3Execution(
RequestMethod.GET,
WxDomain.CHINA.toString(),
WxApiType.GET_CERTIFICATES.toString(),
mchId,
serialNo,
keyPath,
body
);
//平台证书序列号
String serialNumber = MapUtil.getStr(result, "serialNumber");
String body = MapUtil.getStr(result, "body");
int status = MapUtil.getInt(result, "status");
System.out.println("serialNumber:" + serialNumber);
System.out.println("status:" + status);
System.out.println(result);
// 根据证书序列号查询对应的证书来验证签名结果
boolean verifySignature = WxPayKit.verifySignature(result, platformCertPath);
System.out.println("verifySignature:" + verifySignature + "\nbody:" + body);
} catch (Exception e) {
e.printStackTrace();
}
}
案例二:证书报文解密
@Test
public void aesTest() throws GeneralSecurityException {
String associatedData = "";
String nonce = "";
String ciphertext = "";
String saveCertPath = "";
//apikey3是V3API密钥
AesUtil aesUtil = new AesUtil(apiKey3.getBytes(StandardCharsets.UTF_8));
// 平台证书密文解密
//associatedData,nonce,ciphertext这个三个是上面获取平台证书的几个参数
String publicKey = aesUtil.decryptToString(
associatedData.getBytes(StandardCharsets.UTF_8),
nonce.getBytes(StandardCharsets.UTF_8),
ciphertext
);
System.out.println("平台证书公钥明文:" + publicKey);
// 保存证书
//saveCertPath 保存平台证书的路径 例:E:/cert/WXapiclient_cert.pem
FileWriter writer = new FileWriter(saveCertPath);
writer.write(publicKey);
// 获取平台证书序列号
X509Certificate certificate = PayKit.getCertificate(new
ByteArrayInputStream(publicKey.getBytes()));
System.out.println(certificate.getSerialNumber().toString(16).toUpperCase());
}
案例三:带敏感信息请求(就是API参数中有敏感数据需要加密的,和案例一区别就是案例三加了平台证书序列号)
@Test
public void test() throws Exception {
// 带有敏感信息接口
try {
//V3都是用json了,所以用json封装参数,参数详情
//https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/smartguide/chapter3_1.shtml
JSONObject json = new JSONObject()
.set("corpid", "")
.set("store_id", 123456)
.set("userid", "Ta")
.set("name", rsaEncryptOAEP("姓名"))
.set("mobile", rsaEncryptOAEP("手机号"))
.set("qr_code", "")
.set("avatar", "");
String body = JSONUtil.toJsonStr(json);
Map<String, Object> result = WxPayApi.v3Execution(
RequestMethod.POST,
WxDomain.CHINA.toString(),
WxApiType.SMART_GUIDE_GUIDES.toString(),
mchId,
serialNo,
platSerialNumber,//平台证书序列号
keyPath,
body
);
System.out.println(result);
System.out.println(JSONUtil.toJsonStr(result));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 加密敏感信息
* @param data
* @return
* @throws Exception
*/
private String rsaEncryptOAEP(String data) throws Exception {
X509Certificate certificate =
PayKit.getCertificate(FileUtil.getInputStream(platformCertPath));
String encrypt = PayKit.rsaEncryptOAEP(data, certificate);
return encrypt;
}
如果API中没有涉及到敏感数据,可直接ctrl+c+v案例一,改一下请求地址,然后像案例三那样用json封装参数就行了
如果API中有涉及到敏感数据,就要先调用获取平台证书列表,获取到平台证书序列号,然后再请求
案例二主要是用于保存平台证书,用来验证签名
如果接口中带有参数,可使用String.format(WxApiType.SMART_GUIDE_GUIDES_ASSIGN.toString(), "123")
也可以通过https://myssl.com/cert_decode.html把api证书拖进去查看相关信息