Springboot使用OkHttp实现微信支付API-V3签名、证书的管理和使用( 三 )

package com.coderbbb.blogv2.utils;import com.fasterxml.jackson.databind.JsonNode;import javax.crypto.Cipher;import javax.crypto.spec.GCMParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.nio.charset.StandardCharsets;import java.util.Base64;public class AesUtil {private static final int TAG_LENGTH_BIT = 128;public static String aesKey;public static String decryptJsonNodeToString(JsonNode jsonNode){return decryptToString(jsonNode.get("associated_data").asText().getBytes(StandardCharsets.UTF_8),jsonNode.get("nonce").asText().getBytes(StandardCharsets.UTF_8),jsonNode.get("ciphertext").asText());}public static String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) {if (aesKey == null) {throw new RuntimeException("aesKey不能为空");}try {Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");SecretKeySpec key = new SecretKeySpec(aesKey.getBytes(StandardCharsets.UTF_8), "AES");GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);cipher.init(Cipher.DECRYPT_MODE, key, spec);cipher.updateAAD(associatedData);return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);} catch (Exception e) {throw new RuntimeException("aes解密失败", e);}}}package com.coderbbb.blogv2.utils;import com.coderbbb.blogv2.database.dto.WxCertDataDTO;import org.apache.commons.codec.binary.Base64;import org.springframework.core.io.ClassPathResource;import java.nio.charset.StandardCharsets;import java.security.*;import java.security.cert.X509Certificate;import java.util.Enumeration;/** * 微信支付证书解析 * * @author longge93 */public class WxCertUtil {private static WxCertDataDTO wxCertDataDTO = null;public static String keyPass = null;public static String sslPath = "ssl/wx2.p12";private static synchronized WxCertDataDTO loadCert() {if (wxCertDataDTO != null) {return wxCertDataDTO;}if (keyPass == null) {throw new RuntimeException("还没有设置证书密码");}ClassPathResource classPathResource = new ClassPathResource(sslPath);String serialNumber;PublicKey publicKey;PrivateKey privateKey;try {KeyStore keyStore = KeyStore.getInstance("PKCS12");keyStore.load(classPathResource.getInputStream(), keyPass.toCharArray());Enumeration<String> aliases = keyStore.aliases();X509Certificate cert = (X509Certificate) keyStore.getCertificate(aliases.nextElement());//证书序列号serialNumber = cert.getSerialNumber().toString(16).toUpperCase();// 证书公钥publicKey = cert.getPublicKey();// 证书私钥privateKey = (PrivateKey) keyStore.getKey(keyStore.getCertificateAlias(cert), keyPass.toCharArray());} catch (Exception e) {throw new RuntimeException("读取证书失败", e);}wxCertDataDTO = new WxCertDataDTO();wxCertDataDTO.setPublicKey(publicKey);wxCertDataDTO.setPrivateKey(privateKey);wxCertDataDTO.setSerialNumber(serialNumber);wxCertDataDTO.setMchId(keyPass);return wxCertDataDTO;}public static WxCertDataDTO getCert() {if (wxCertDataDTO != null) {return wxCertDataDTO;}return loadCert();}public static String rsaSign(String signatureStr){WxCertDataDTO wxCertDataDTO = getCert();try {Signature sign = Signature.getInstance("SHA256withRSA");sign.initSign(wxCertDataDTO.getPrivateKey());sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));return Base64.encodeBase64String(sign.sign());} catch (Exception e) {throw new RuntimeException("RSA签名失败");}}}源代码使用方法

  • 首先 , 你得pom引入OkHttp和apache-commons-lang3(可能有遗漏 , 你如果有报错 , 就自己加一下)
<dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.1</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency>
  • 然后 , 把上面依赖的OkHttpUtil、AesUtil、WxCertUtil和WxOkHttpUtil放到一起 , 把报错的import改一改(因为你和我的包名不一样 , 肯定会报错)
  • 关于证书管理:我的策略是 , 每次程序启动(或定时任务) , 都会调用微信的接口 , 下载微信平台证书 , 保存到数据库 , 再保存到静态变量中WxOkHttpUtil类的WX_PLAT_CERT变量 。(所以 , 你使用代码时 , 应该先调用下载WxOkHttpUtil中下载证书的接口 , 把证书加载到这个变量中 , 然后才能正常执行微信下单、退款等等操作)
  • WxCertUtil.keyPass是证书的密码 , 其实就是微信商户号
  • AesUtil.aesKey 就是前面接入准备中提到的API KEY
其他到这一步 , 微信支付API-V3的各种安全校验问题应该是解决了 , 专栏下一篇就介绍怎么使用本文封装好的HTTP GET、HTTP POST来完成整个微信支付流程 。


推荐阅读