在微信支付商户配置中获取所需商户证书
Method 1 : 通过商户证书获取平台证书放入header直接请求转账接口
进入上面图片中证书所在目录,执行以下命令查看证书序列号
openssl x509 -in apiclient_cert.pem -inform der -noout -text
返回
serial=123456
public static void main(String[] args) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException {
String url = "https://api.mch.weixin.qq.com/v3/certificates";
String schema = "WECHATPAY2-SHA256-RSA2048 ";
HttpGet httpGet = new HttpGet(url);
String token = getToken("GET", HttpUrl.parse(url),"");
httpGet.addHeader("Accept", "application/json");
httpGet.setHeader("Authorization",schema + token);
CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse response = client.execute(httpGet);
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
result = EntityUtils.toString(entity, "UTF8");
System.out.println(">>>>>>>>>>>>>>>" + result);
}
response.close();
}
private static String getToken(String method, HttpUrl url, String body) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, FileNotFoundException {
String nonceStr = "随机32位字符串";
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes("utf-8"));
return "mchid=\"" + "开通支付的商户号" + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + serial + "\","
+ "signature=\"" + signature + "\"";
}
private static String sign(byte[] message) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, FileNotFoundException {
Signature sign = Signature.getInstance("SHA256withRSA");
File file = new File("apiclient_key.pem");
InputStream inputStream = new FileInputStream(file);
sign.initSign(PemUtils.loadPrivateKey(inputStream));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
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";
}
解密响应的json
/**
* 解密响应体.
*
* @param apiV3Key API V3 KEY API v3密钥 商户平台设置的32位字符串
* @param associatedData response.body.data[i].encrypt_certificate.associated_data
* @param nonce response.body.data[i].encrypt_certificate.nonce
* @param ciphertext response.body.data[i].encrypt_certificate.ciphertext
* @return the string
* @throws GeneralSecurityException the general security exception
*/
public static String decryptResponseBody(String apiV3Key, String associatedData, String nonce, String ciphertext) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
byte[] bytes;
try {
bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));
} catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e);
}
return new String(bytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}
Method2 :通过sdk自动初始化平台证书发起请求
public WxPayService getWxPayServiceV2(WechatMerchantEntity wechatMerchant) {
//先确定平台端的商户配置
WechatMerchantEntity serviceMerchant = wechatMerchantDAO.getByMerchantNoAndAppid(wechatMerchant.getMerchantNo(),wechatMerchant.getAppId());
List<CompanyAttributeEntity> companyAttributes = companyAttributeDAO.selectByMerchatId(serviceMerchant.getId());
if (CollUtil.isEmpty(companyAttributes)) {
throw new BusinessException(ResultEnum.WX_PAY_CONFIG_NOT_EXIST);
}
Map<String, CompanyAttributeEntity> companyAttributeMap = companyAttributes.stream()
.collect(Collectors.toMap(CompanyAttributeEntity::getConfigKey, companyAttribute -> companyAttribute));
WxPayService wxPayService = new WxPayServiceImpl();
WxPayConfig wxPayConfig = new WxPayConfig();
//平台appid
wxPayConfig.setAppId(serviceMerchant.getAppId());
//服务商商户号
wxPayConfig.setMchId(serviceMerchant.getMerchantNo());
//服务商的秘钥
wxPayConfig.setMchKey(StringUtils.trimToNull(companyAttributeMap.get(MCH_KEY).getValueText()));
//apiV3 秘钥值
wxPayConfig.setApiV3Key(StringUtils.trimToNull(companyAttributeMap.get(MCH_KEY).getValueText()));
//apiV3 证书序列号值
wxPayConfig.setCertSerialNo(StringUtils.trimToNull(companyAttributeMap.get(SERIAL_NO).getValueText()));
//服务商证书
if (companyAttributeMap.get("apiclient_cert.p12") != null &&
companyAttributeMap.get(CERTIFICATE).getValueBlob() != null) {
try {
byte[] key = new byte[8096];
int read = new ByteArrayInputStream(companyAttributeMap.get("apiclient_cert.p12").getValueBlob()).read(key);
wxPayConfig.setKeyContent(key);
log.info("----->apiclient_cert.p12证书文件长度:[{}]<----", read);
String path = "apiclient_key.pem";
File file = new File(path);
InputStream inputStream = new FileInputStream(file);
//apiclient_key.pem证书文件内容的字节数组.
wxPayConfig.setPrivateKeyContent(streamToByte(inputStream));
log.info("----->apiclient_key证书文件长度:[{}]<----", wxPayConfig.getPrivateKeyContent().length);
String path2 = "apiclient_cert.pem";
File file2 = new File(path2);
InputStream inputStream2 = new FileInputStream(file2);
//apiclient_cert.pem证书文件内容的字节数组.
wxPayConfig.setPrivateCertContent(streamToByte(inputStream2));
} catch (IOException e) {
log.error(" io exception", e);
}
}
wxPayService.setConfig(wxPayConfig);
return wxPayService;
}
public static byte[] streamToByte(InputStream is) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int i = -1;
try {
//将输入流中的数据读到bytes中,i表示bytes的长度,当读完时i=-1退出循环
while ((i = is.read(bytes)) != -1) {
//将指定的字节数组从偏移量off开始,写入i个字节到输出流
bos.write(bytes, 0, i);
}
} catch (Exception e) {
e.printStackTrace();
}
return bos.toByteArray();
}