最近微信商戶給老闆推送了一個支付即服務的功能,老闆看到了就想要,好吧,那就搞吧,看流程挺簡單的
但是是微信支付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";//微信平臺證書 驗證簽名時需要使用
案例一 :獲取平臺證書(如果所需要的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證書拖進去查看相關信息