diff --git a/IJPay-Core/pom.xml b/IJPay-Core/pom.xml index 7d0235489984ab4dde69eb630928c2b20e5e0427..c6f8208828c58099e6cd05ba4e930f4790faba34 100644 --- a/IJPay-Core/pom.xml +++ b/IJPay-Core/pom.xml @@ -51,5 +51,11 @@ xk-time ${xk.time.version} + + org.bouncycastle + bcprov-jdk15on + 1.62 + compile + diff --git a/IJPay-Core/src/main/java/com/ijpay/core/enums/AuthTypeEnum.java b/IJPay-Core/src/main/java/com/ijpay/core/enums/AuthTypeEnum.java index c13929cbd3389b6a098a64f92cbe32faee4eb444..a8fc5221a06c3f18da06b195a34413641ae65b18 100644 --- a/IJPay-Core/src/main/java/com/ijpay/core/enums/AuthTypeEnum.java +++ b/IJPay-Core/src/main/java/com/ijpay/core/enums/AuthTypeEnum.java @@ -18,29 +18,32 @@ public enum AuthTypeEnum { /** * 国密 */ - SM("WECHATPAY2-SM2-WITH-SM3", "国密算法"), + SM2("WECHATPAY2-SM2-WITH-SM3", "AEAD_SM4_GCM", "国密算法"), /** * RSA */ - RSA("WECHATPAY2-SHA256-RSA2048", "RSA算法"), + RSA("WECHATPAY2-SHA256-RSA2048", "AEAD_AES_256_GCM", "RSA算法"), ; - private final String url; + private final String code; + + private final String platformCertAlgorithm; private final String desc; - AuthTypeEnum(String url, String desc) { - this.url = url; + AuthTypeEnum(String code, String platformCertAlgorithm, String desc) { + this.code = code; + this.platformCertAlgorithm = platformCertAlgorithm; this.desc = desc; } /** - * 获取枚举URL + * 获取枚举编码 * * @return 枚举编码 */ - public String getUrl() { - return url; + public String getCode() { + return code; } /** @@ -51,4 +54,13 @@ public enum AuthTypeEnum { public String getDesc() { return desc; } + + /** + * 获取平台证书算法 + * + * @return 平台证书算法 + */ + public String getPlatformCertAlgorithm() { + return platformCertAlgorithm; + } } diff --git a/IJPay-Core/src/main/java/com/ijpay/core/kit/PayKit.java b/IJPay-Core/src/main/java/com/ijpay/core/kit/PayKit.java index 597f3fe5ff7ed865a8816b6be911ab131ccbb647..4b16a02fd90e10a1031517a4ce3a8889f6a3730d 100644 --- a/IJPay-Core/src/main/java/com/ijpay/core/kit/PayKit.java +++ b/IJPay-Core/src/main/java/com/ijpay/core/kit/PayKit.java @@ -14,13 +14,18 @@ import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.digest.HmacAlgorithm; import com.ijpay.core.XmlHelper; import com.ijpay.core.constant.IJPayConstants; +import com.ijpay.core.enums.AuthTypeEnum; import com.ijpay.core.enums.RequestMethodEnum; import com.ijpay.core.model.CertificateModel; +import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import org.bouncycastle.jce.provider.BouncyCastleProvider; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -28,21 +33,11 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateFactory; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.security.*; +import java.security.cert.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.*; /** *

IJPay 让支付触手可及,封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。

@@ -63,6 +58,138 @@ public class PayKit { */ public static final String CLASS_PATH_PREFIX = "classpath:"; + + /** + * 获取国密证书私钥 + * + * @param privateKey 私钥 + * @return 返回值 + * @throws Exception 异常信息 + */ + public static PrivateKey getSmPrivateKey(String privateKey) throws Exception { + byte[] encPrivate = Base64.decode(privateKey); + return getSmPrivateKey(encPrivate); + } + + /** + * 获取国密证书公钥 + * + * @param publicKey 公钥 + * @return 返回值 + * @throws Exception 异常信息 + */ + public static PublicKey getSmPublicKey(String publicKey) throws Exception { + byte[] encPublic = Base64.decode(publicKey); + return getSmPublicKey(encPublic); + } + + /** + * 获取国密证书私钥 + * + * @param encPrivate 私钥 + * @return 返回值 + * @throws Exception 异常信息 + */ + public static PrivateKey getSmPrivateKey(byte[] encPrivate) throws Exception { + KeyFactory keyFact = KeyFactory.getInstance("EC", new BouncyCastleProvider()); + return keyFact.generatePrivate(new PKCS8EncodedKeySpec(encPrivate)); + } + + /** + * 获取国密证书公钥 + * + * @param encPublic 公钥 + * @return 返回值 + * @throws Exception 异常信息 + */ + public static PublicKey getSmPublicKey(byte[] encPublic) throws Exception { + KeyFactory keyFact = KeyFactory.getInstance("EC", new BouncyCastleProvider()); + return keyFact.generatePublic(new X509EncodedKeySpec(encPublic)); + } + + /** + * 签名 + * + * @param privateKey 私钥 + * @param content 需要签名的内容 + * @return 返回结果 + * @throws Exception 异常信息 + */ + public static String sm2SignWithSm3(String privateKey, String content) throws Exception { + PrivateKey smPrivateKey = getSmPrivateKey(privateKey); + return sm2SignWithSm3(smPrivateKey, content); + } + + /** + * 签名 + * + * @param privateKey 私钥 + * @param content 需要签名的内容 + * @return 返回结果 + * @throws Exception 异常信息 + */ + public static String sm2SignWithSm3(PrivateKey privateKey, String content) throws Exception { + // 生成SM2sign with sm3 签名验签算法实例 + Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString() + , new BouncyCastleProvider()); + // 使用私钥签名,初始化签名实例 + signature.initSign(privateKey); + // 签名原文 + byte[] plainText = content.getBytes(StandardCharsets.UTF_8); + // 写入签名原文到算法中 + signature.update(plainText); + // 计算签名值 + byte[] signatureValue = signature.sign(); + return Base64.encode(signatureValue); + } + + /** + * SM3 Hash + * + * @param content 原始内容 + * @return 返回结果 + * @throws Exception 异常信息 + */ + public static byte[] sm3Hash(String content) throws Exception { + MessageDigest digest = MessageDigest.getInstance("SM3", new BouncyCastleProvider()); + byte[] contentDigest = digest.digest(content.getBytes(StandardCharsets.UTF_8)); + return Arrays.copyOf(contentDigest, 16); + } + + /** + * 下载平台证书以及回调通知加解密 + * + * @param key3 APIv3密钥 + * @param cipherText 密文 + * @param nonce 随机串 + * @param associatedData 附加数据 + * @return 解密后的明文 + * @throws Exception 异常信息 + */ + public static String sm4DecryptToString(String key3, String cipherText, String nonce, String associatedData) throws Exception { + Cipher cipher = Cipher.getInstance("SM4/GCM/NoPadding", new BouncyCastleProvider()); + byte[] keyByte = PayKit.sm3Hash(key3); + SecretKeySpec key = new SecretKeySpec(keyByte, "SM4"); + GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8)); + cipher.init(Cipher.DECRYPT_MODE, key, spec); + cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8)); + return new String(cipher.doFinal(Base64.decode(cipherText)), StandardCharsets.UTF_8); + } + + public static boolean sm4Verify(String publicKey, String plainText, String originalSignature) throws Exception { + PublicKey smPublicKey = getSmPublicKey(publicKey); + return sm4Verify(smPublicKey, plainText, originalSignature); + } + + public static boolean sm4Verify(PublicKey publicKey, String data, String originalSignature) throws Exception { + Signature signature = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString() + , new BouncyCastleProvider()); + signature.initVerify(publicKey); + // 写入待验签的签名原文到算法中 + signature.update(data.getBytes(StandardCharsets.UTF_8)); + return signature.verify(Base64.decode(originalSignature.getBytes(StandardCharsets.UTF_8))); + } + /** * 生成16进制的 sha256 字符串 * @@ -321,7 +448,7 @@ public class PayKit { * @return 构造后带待签名串 */ public static String buildSignMessage(ArrayList signMessage) { - if (signMessage == null || signMessage.size() <= 0) { + if (signMessage == null || signMessage.size() == 0) { return null; } StringBuilder sbf = new StringBuilder(); @@ -339,8 +466,8 @@ public class PayKit { * @return 生成 v3 签名 * @throws Exception 异常信息 */ - public static String createSign(ArrayList signMessage, String keyPath) throws Exception { - return createSign(buildSignMessage(signMessage), keyPath); + public static String createSign(ArrayList signMessage, String keyPath, String authType) throws Exception { + return createSign(buildSignMessage(signMessage), keyPath, authType); } /** @@ -364,13 +491,16 @@ public class PayKit { * @return 生成 v3 签名 * @throws Exception 异常信息 */ - public static String createSign(String signMessage, String keyPath) throws Exception { + public static String createSign(String signMessage, String keyPath, String authType) throws Exception { if (StrUtil.isEmpty(signMessage)) { return null; } // 获取商户私钥 - PrivateKey privateKey = PayKit.getPrivateKey(keyPath); + PrivateKey privateKey = PayKit.getPrivateKey(keyPath, authType); // 生成签名 + if (StrUtil.equals(authType, AuthTypeEnum.SM2.getCode())) { + return sm2SignWithSm3(privateKey, signMessage); + } return RsaKit.encryptByPrivateKey(signMessage, privateKey); } @@ -418,8 +548,8 @@ public class PayKit { * @return {@link String} 商户私钥 * @throws Exception 异常信息 */ - public static String getPrivateKeyStr(String keyPath) throws Exception { - return RsaKit.getPrivateKeyStr(getPrivateKey(keyPath)); + public static String getPrivateKeyStr(String keyPath, String authType) throws Exception { + return RsaKit.getPrivateKeyStr(getPrivateKey(keyPath, authType)); } /** @@ -429,12 +559,12 @@ public class PayKit { * @return {@link PrivateKey} 商户私钥 * @throws Exception 异常信息 */ - public static PrivateKey getPrivateKey(String keyPath) throws Exception { + public static PrivateKey getPrivateKey(String keyPath, String authType) throws Exception { String originalKey = getCertFileContent(keyPath); if (StrUtil.isEmpty(originalKey)) { throw new RuntimeException("商户私钥证书获取失败"); } - return getPrivateKeyByKeyContent(originalKey); + return getPrivateKeyByKeyContent(originalKey, authType); } /** @@ -444,8 +574,11 @@ public class PayKit { * @return {@link PrivateKey} 商户私钥 * @throws Exception 异常信息 */ - public static PrivateKey getPrivateKeyByKeyContent(String originalKey) throws Exception { + public static PrivateKey getPrivateKeyByKeyContent(String originalKey, String authType) throws Exception { String privateKey = getPrivateKeyByContent(originalKey); + if (StrUtil.equals(authType, AuthTypeEnum.SM2.getCode())) { + return getSmPrivateKey(privateKey); + } return RsaKit.loadPrivateKey(privateKey); } @@ -470,7 +603,8 @@ public class PayKit { */ public static X509Certificate getCertificate(InputStream inputStream) { try { - CertificateFactory cf = CertificateFactory.getInstance("X509"); + Security.addProvider(new BouncyCastleProvider()); + CertificateFactory cf = CertificateFactory.getInstance("X.509", new BouncyCastleProvider()); X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); cert.checkValidity(); return cert; @@ -550,11 +684,6 @@ public class PayKit { if (null == notAfter) { return false; } - // 证书颁发者 - Principal issuerDn = model.getIssuerDn(); - if (null == issuerDn || !issuerDn.getName().contains(IJPayConstants.ISSUER)) { - return false; - } // 证书CN字段 if (StrUtil.isNotEmpty(mchId)) { Principal subjectDn = model.getSubjectDn(); diff --git a/IJPay-Core/src/main/java/com/ijpay/core/kit/WxPayKit.java b/IJPay-Core/src/main/java/com/ijpay/core/kit/WxPayKit.java index 0a6f7f47a4109455a953a2f5a5243ab7d5eecacc..441772c46a7ee6b5d8b53b001032fd98fbddbb35 100644 --- a/IJPay-Core/src/main/java/com/ijpay/core/kit/WxPayKit.java +++ b/IJPay-Core/src/main/java/com/ijpay/core/kit/WxPayKit.java @@ -378,7 +378,7 @@ public class WxPayKit { * @throws Exception 错误信息 */ public static Map jsApiCreateSign(String appId, String prepayId, String keyPath) throws Exception { - return jsApiCreateSign(appId, prepayId, PayKit.getPrivateKey(keyPath)); + return jsApiCreateSign(appId, prepayId, PayKit.getPrivateKey(keyPath, AuthTypeEnum.RSA.getCode())); } /** @@ -451,7 +451,7 @@ public class WxPayKit { * @throws Exception 错误信息 */ public static Map appCreateSign(String appId, String partnerId, String prepayId, String keyPath) throws Exception { - return appCreateSign(appId, partnerId, prepayId, PayKit.getPrivateKey(keyPath)); + return appCreateSign(appId, partnerId, prepayId, PayKit.getPrivateKey(keyPath, AuthTypeEnum.RSA.getCode())); } /** @@ -533,7 +533,7 @@ public class WxPayKit { long timestamp, String authType) throws Exception { // 构建签名参数 String buildSignMessage = PayKit.buildSignMessage(method, urlSuffix, timestamp, nonceStr, body); - String signature = PayKit.createSign(buildSignMessage, keyPath); + String signature = PayKit.createSign(buildSignMessage, keyPath, authType); // 根据平台规则生成请求头 authorization return PayKit.getAuthorization(mchId, serialNo, nonceStr, String.valueOf(timestamp), signature, authType); } @@ -579,7 +579,7 @@ public class WxPayKit { String serialNo, String keyPath, String body) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); + String authType = AuthTypeEnum.RSA.getCode(); String nonceStr = PayKit.generateStr(); return buildAuthorization(method, urlSuffix, mchId, serialNo, keyPath, body, nonceStr, timestamp, authType); @@ -601,9 +601,8 @@ public class WxPayKit { String serialNo, PrivateKey privateKey, String body) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); + String authType = AuthTypeEnum.RSA.getCode(); String nonceStr = PayKit.generateStr(); - return buildAuthorization(method, urlSuffix, mchId, serialNo, privateKey, body, nonceStr, timestamp, authType); } @@ -621,7 +620,8 @@ public class WxPayKit { String body = (String) map.get("body"); String nonceStr = (String) map.get("nonceStr"); String timestamp = (String) map.get("timestamp"); - return verifySignature(signature, body, nonceStr, timestamp, PayKit.getCertFileInputStream(certPath)); + String signatureType = (String) map.get("Wechatpay-Signature-Type"); + return verifySignature(signatureType, signature, body, nonceStr, timestamp, PayKit.getCertFileInputStream(certPath)); } /** @@ -636,8 +636,14 @@ public class WxPayKit { String timestamp = response.getHeader("Wechatpay-Timestamp"); String nonceStr = response.getHeader("Wechatpay-Nonce"); String signature = response.getHeader("Wechatpay-Signature"); + String signatureType = response.getHeader("Wechatpay-Signature-Type"); String body = response.getBody(); - return verifySignature(signature, body, nonceStr, timestamp, PayKit.getCertFileInputStream(certPath)); + System.out.println("timestamp:" + timestamp); + System.out.println("nonceStr:" + nonceStr); + System.out.println("signature:" + signature); + System.out.println("signatureType:" + signatureType); + System.out.println("body:" + body); + return verifySignature(signatureType, signature, body, nonceStr, timestamp, PayKit.getCertFileInputStream(certPath)); } /** @@ -652,8 +658,9 @@ public class WxPayKit { String timestamp = response.getHeader("Wechatpay-Timestamp"); String nonceStr = response.getHeader("Wechatpay-Nonce"); String signature = response.getHeader("Wechatpay-Signature"); + String signatureType = response.getHeader("Wechatpay-Signature-Type"); String body = response.getBody(); - return verifySignature(signature, body, nonceStr, timestamp, certInputStream); + return verifySignature(signatureType, signature, body, nonceStr, timestamp, certInputStream); } /** @@ -670,7 +677,8 @@ public class WxPayKit { String body = (String) map.get("body"); String nonceStr = (String) map.get("nonceStr"); String timestamp = (String) map.get("timestamp"); - return verifySignature(signature, body, nonceStr, timestamp, certInputStream); + String signatureType = (String) map.get("Wechatpay-Signature-Type"); + return verifySignature(signatureType, signature, body, nonceStr, timestamp, certInputStream); } /** @@ -708,6 +716,7 @@ public class WxPayKit { /** * 验证签名 * + * @param signatureType 签名类型 * @param signature 待验证的签名 * @param body 应答主体 * @param nonce 随机串 @@ -716,11 +725,14 @@ public class WxPayKit { * @return 签名结果 * @throws Exception 异常信息 */ - public static boolean verifySignature(String signature, String body, String nonce, String timestamp, InputStream certInputStream) throws Exception { + public static boolean verifySignature(String signatureType, String signature, String body, String nonce, String timestamp, InputStream certInputStream) throws Exception { String buildSignMessage = PayKit.buildSignMessage(timestamp, nonce, body); // 获取证书 X509Certificate certificate = PayKit.getCertificate(certInputStream); PublicKey publicKey = certificate.getPublicKey(); + if (StrUtil.equals(signatureType, AuthTypeEnum.SM2.getCode())) { + return PayKit.sm4Verify(publicKey, buildSignMessage, signature); + } return RsaKit.checkByPublicKey(buildSignMessage, signature, publicKey); } diff --git a/IJPay-WxPay/src/main/java/com/ijpay/wxpay/WxPayApi.java b/IJPay-WxPay/src/main/java/com/ijpay/wxpay/WxPayApi.java index d7bbf01203be3cb340ebacb6bed036d387cc77bf..3093988a69b728ab6e9a4447e1fe02ecd388bb71 100644 --- a/IJPay-WxPay/src/main/java/com/ijpay/wxpay/WxPayApi.java +++ b/IJPay-WxPay/src/main/java/com/ijpay/wxpay/WxPayApi.java @@ -13,14 +13,7 @@ import com.ijpay.core.kit.WxPayKit; import com.ijpay.wxpay.enums.WxApiEnum; import com.ijpay.wxpay.enums.WxDomain; import com.ijpay.wxpay.enums.WxDomainEnum; -import com.ijpay.wxpay.enums.v2.CouponApiEnum; -import com.ijpay.wxpay.enums.v2.DepositApiEnum; -import com.ijpay.wxpay.enums.v2.EntrustPayApiEnum; -import com.ijpay.wxpay.enums.v2.FacePayApiEnum; -import com.ijpay.wxpay.enums.v2.PayApiEnum; -import com.ijpay.wxpay.enums.v2.ProfitSharingApiEnum; -import com.ijpay.wxpay.enums.v2.RedPackApiEnum; -import com.ijpay.wxpay.enums.v2.TransferApiEnum; +import com.ijpay.wxpay.enums.v2.*; import java.io.File; import java.io.InputStream; @@ -340,17 +333,37 @@ public class WxPayApi { * @param platSerialNo 平台序列号 * @param keyPath apiclient_key.pem 证书路径 * @param body 接口请求参数 + * @param authType 认证类型 * @return {@link IJPayHttpResponse} 请求返回的结果 * @throws Exception 接口执行异常 */ public static IJPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId, - String serialNo, String platSerialNo, String keyPath, String body) throws Exception { + String serialNo, String platSerialNo, String keyPath, String body, String authType) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); String nonceStr = WxPayKit.generateStr(); return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, null); } + /** + * V3 接口统一执行入口 + * + * @param method {@link RequestMethodEnum} 请求方法 + * @param urlPrefix 可通过 {@link WxDomain}来获取 + * @param urlSuffix 可通过 {@link WxApiEnum} 来获取,URL挂载参数需要自行拼接 + * @param mchId 商户Id + * @param serialNo 商户 API 证书序列号 + * @param platSerialNo 平台序列号 + * @param keyPath apiclient_key.pem 证书路径 + * @param body 接口请求参数 + * @return {@link IJPayHttpResponse} 请求返回的结果 + * @throws Exception 接口执行异常 + */ + public static IJPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId, + String serialNo, String platSerialNo, String keyPath, String body) throws Exception { + String authType = AuthTypeEnum.RSA.getCode(); + return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, authType); + } + /** * V3 接口统一执行入口 * @@ -368,7 +381,7 @@ public class WxPayApi { public static IJPayHttpResponse v3(RequestMethodEnum method, String urlPrefix, String urlSuffix, String mchId, String serialNo, String platSerialNo, PrivateKey privateKey, String body) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); + String authType = AuthTypeEnum.RSA.getCode(); String nonceStr = WxPayKit.generateStr(); return v3(method, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, body, nonceStr, timestamp, authType, null); } @@ -391,7 +404,7 @@ public class WxPayApi { String mchId, String serialNo, String platSerialNo, String keyPath, Map params) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); + String authType = AuthTypeEnum.RSA.getCode(); String nonceStr = WxPayKit.generateStr(); if (null != params && !params.keySet().isEmpty()) { urlSuffix = urlSuffix.concat("?").concat(PayKit.createLinkString(params, true)); @@ -417,7 +430,7 @@ public class WxPayApi { String mchId, String serialNo, String platSerialNo, PrivateKey privateKey, Map params) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); + String authType = AuthTypeEnum.RSA.getCode(); String nonceStr = WxPayKit.generateStr(); if (null != params && !params.keySet().isEmpty()) { urlSuffix = urlSuffix.concat("?").concat(PayKit.createLinkString(params, true)); @@ -441,7 +454,7 @@ public class WxPayApi { */ public static IJPayHttpResponse v3(String urlPrefix, String urlSuffix, String mchId, String serialNo, String platSerialNo, String keyPath, String body, File file) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); + String authType = AuthTypeEnum.RSA.getCode(); String nonceStr = WxPayKit.generateStr(); return v3(RequestMethodEnum.UPLOAD, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, keyPath, body, nonceStr, timestamp, authType, file); } @@ -463,7 +476,7 @@ public class WxPayApi { public static IJPayHttpResponse v3(String urlPrefix, String urlSuffix, String mchId, String serialNo, String platSerialNo, PrivateKey privateKey, String body, File file) throws Exception { long timestamp = System.currentTimeMillis() / 1000; - String authType = AuthTypeEnum.RSA.getUrl(); + String authType = AuthTypeEnum.RSA.getCode(); String nonceStr = WxPayKit.generateStr(); return v3(RequestMethodEnum.UPLOAD, urlPrefix, urlSuffix, mchId, serialNo, platSerialNo, privateKey, body, nonceStr, timestamp, authType, file); }