1掸刊、介紹
微信支付平臺證書是指由微信支付負(fù)責(zé)申請的,包含微信支付平臺標(biāo)識赢乓、公鑰信息的證書忧侧。商戶可以使用平臺證書中的公鑰進(jìn)行驗簽。注意骏全,這里的證書區(qū)別于商戶API證書,商戶API證書是直接從商戶后臺下載查看的尼斧,而微信支付平臺證書是通過電商收付通的證書接口獲取的姜贡。
2、作用
這個證書有什么用棺棵?我們需要獲取到這個證書相關(guān)的序列號和公鑰楼咳,后續(xù)請求一系列接口時需要將微信支付平臺證書序列號放在請求頭里熄捍,而公鑰是為了驗證應(yīng)答或回調(diào)的簽名,以確保應(yīng)答或回調(diào)是由微信支付發(fā)送母怜。
3余耽、獲取微信支付平臺證書
注意:不同的商戶,對應(yīng)的微信支付平臺證書是不一樣的苹熏,平臺證書會周期性更換碟贾。建議商戶定時通過API下載新的證書,不要依賴人工更換證書轨域。微信支付的平臺證書序列號位于HTTP頭Wechatpay-Serial袱耽。驗證簽名前,請商戶先檢查序列號是否跟商戶當(dāng)前所持有的微信支付平臺證書的序列號一致干发。如果不一致朱巨,請重新獲取證書。否則枉长,簽名的私鑰和證書不匹配冀续,將無法成功驗證簽名。雙手奉上獲取微信支付
/**
* @date 2020-03-18 15:06
* @description
*/
public class Certificate {
private static final Logger logger = LoggerFactory.getLogger(Certificate.class);
/**
* 獲取微信支付平臺證書
* @param merchantId
* @param timeout
* @param serialNo
* @param mchPrivateKeyPath
* @param APIv3Key
* @param savePath
* @return
*/
public static List<X509Certificate> getCertByAPI(String merchantId, int timeout, String serialNo, String mchPrivateKeyPath,String wechatPubKeyPath,String APIv3Key,String savePath) {
String result = "";
//創(chuàng)建http請求
HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com
/v3/certificates");
httpGet.addHeader("Content-Type", "application/json");
httpGet.addHeader("Accept", "application/json");
String authorization = SignUtils.authorization("GET", "/v3/certificates", merchantId, serialNo, "", mchPrivateKeyPath);
//設(shè)置認(rèn)證信息
httpGet.setHeader("Authorization", authorization);
//設(shè)置請求器配置:如超時限制等
RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout * 1000).setConnectTimeout(timeout * 1000).build();
httpGet.setConfig(config);
List<X509Certificate> x509Certs = new ArrayList<X509Certificate>();
try {
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
HttpEntity httpEntity = response.getEntity();
result = EntityUtils.toString(httpEntity, "UTF-8");
if(statusCode == 200){
logger.info("下載平臺證書返回結(jié)果:"+result);
Header[] timestampHeader = response.getHeaders("Wechatpay-Timestamp");
Header[] nonceHeader = response.getHeaders("Wechatpay-Nonce");
Header[] signatureHeader = response.getHeaders("Wechatpay-Signature");
if (timestampHeader != null && timestampHeader.length > 0 &&
nonceHeader != null && nonceHeader.length > 0 &&
signatureHeader != null && signatureHeader.length > 0) {
// 驗證微信支付返回簽名
String wTimestamp = timestampHeader[0].getValue();
String wNonce = nonceHeader[0].getValue();
String wSign = signatureHeader[0].getValue();
logger.info("wTimestamp:{}必峰,wNonce:{}洪唐,wSign:{}", wTimestamp, wNonce, wSign);
// 拼裝待簽名串
StringBuffer ss = new StringBuffer();
ss.append(wTimestamp).append("\n");
ss.append(wNonce).append("\n");
ss.append(result).append("\n");
// 驗證簽名
if (SignUtils.v3VerifyRSA(ss.toString(), Base64.decodeBase64(wSign.getBytes()), wechatPubKeyPath)) {
List<CertificateItem> certList = new ArrayList<CertificateItem>();
JSONObject json = JSONObject.parseObject(result);
logger.info("查詢結(jié)果json字符串轉(zhuǎn)證書List:" + json.get("data"));
JSONArray jsonArray = (JSONArray) json.get("data");
for (int i = 0; i < jsonArray.size(); i++) {
CertificateItem certificateItem = new CertificateItem();
EncryptedCertificateItem encryptCertificate = new EncryptedCertificateItem();
JSONObject bo = JSONObject.parseObject(jsonArray.get(i).toString());
certificateItem.setSerial_no(bo.get("serial_no").toString());
certificateItem.setEffective_time(bo.get("effective_time").toString());
certificateItem.setExpire_time(bo.get("expire_time").toString());
JSONObject encryptBo = JSONObject.parseObject(bo.get("encrypt_certificate").toString());
encryptCertificate.setAlgorithm(encryptBo.get("algorithm").toString());
encryptCertificate.setNonce(encryptBo.get("nonce").toString());
encryptCertificate.setAssociated_data(encryptBo.get("associated_data").toString());
encryptCertificate.setCiphertext(encryptBo.get("ciphertext").toString());
certificateItem.setEncrypt_certificate(encryptCertificate);
certList.add(certificateItem);
}
logger.info("證書List:" + certList);
List<PlainCertificateItem> plainList = decrypt(certList, APIv3Key);
if (CollectionUtils.isNotEmpty(plainList)) {
logger.info("平臺證書開始保存");
x509Certs = saveCertificate(plainList, savePath);
}
}
}
}
response.close();
httpClient.close(); //throw
return x509Certs;
} catch (Exception e) {
e.printStackTrace();
logger.error("下載平臺證書返回結(jié)果:"+e);
}
return x509Certs;
}
4、結(jié)果
1自点、接口返回的內(nèi)容是json串
{
"data": [{
"serial_no": "5157F09EFDC096DE15EBE81A47057A7232F1B8E1",
"effective_time ": "2018-06-08T10:34:56+08:00",
"expire_time ": "2018-12-08T10:34:56+08:00",
"encrypt_certificate": {
"algorithm": "AEAD_AES_256_GCM",
"nonce": "61f9c719728a",
"associated_data": "certificate",
"ciphertext": "sRvt… "
}
}]
}
2桐罕、通過接口下載的微信支付平臺證書