微信支付对接用到的商户API证书是PKCS12格式,常见后缀名是.p12。调用微信支付接口时,都需要用到私钥和证书序列号,为了方便用户,所以一般要求用户直接上传证书(.p12文件),再由后台解析私钥和证书序列号。 而且因为证书本身是一个文件,不方便存储到数据库,所以也转成BASE64格式后再存储。
直接上代码
public class P12Application {
public static void main(String[] args) throws Exception {
//从文件中解析
try (FileInputStream is = new FileInputStream("apiclient.p12")) {
System.out.println(P12Info.parse(is, "证书密码"));
}
//从Base64加密串中解析
String p12Base64 = "xxxyyyzzz";
byte[] base64byte = Base64.getDecoder().decode(p12Base64);
try (ByteArrayInputStream is = new ByteArrayInputStream(base64byte)) {
System.out.println(P12Info.parse(is, "证书密码"));
}
}
@Data
@Builder
private static class P12Info {
/**
* 证书序列号.
*/
private final String serialNo;
/**
* 证书秘钥.
*/
private final PrivateKey privateKey;
/**
* 公钥.
*/
private final PublicKey publicKey;
public static P12Info parse(InputStream is, String passwd) throws Exception {
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(is, passwd.toCharArray());
String keyAlias = null;
//解析证书,必须有别名
Enumeration<String> aliases = ks.aliases();
if (aliases.hasMoreElements()) {
keyAlias = aliases.nextElement();
}
//解析私钥
PrivateKey privateKey = (PrivateKey) ks.getKey(keyAlias, passwd.toCharArray());
Certificate cert = ks.getCertificate(keyAlias);
BigInteger serialNumber = ((X509CertImpl) cert).getSerialNumber();
//证书一般都使用16进制表示
String certSn = serialNumber.toString(16);
//设置证书序列号和私钥
return P12Info.builder()
.serialNo(certSn)
.privateKey(privateKey)
.publicKey(cert.getPublicKey())
.build();
}
}
}
常见问题
- 解析的私钥和公钥都是空:需要检查证书别名是否正确
网友评论