From 3e2d05a769c42be505e4272292ac4ce86ae0c49b Mon Sep 17 00:00:00 2001 From: egan Date: Thu, 14 Aug 2025 10:39:30 +0800 Subject: [PATCH] =?UTF-8?q?2.14.9=20=E5=BE=AE=E4=BF=A1=E5=85=AC=E9=92=A5?= =?UTF-8?q?=E8=AF=81=E4=B9=A6=E6=94=AF=E6=8C=81=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?pem=E8=AF=81=E4=B9=A6=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pay-java-ali/pom.xml | 2 +- pay-java-ali/src/test/java/PayTest.java | 21 ++-- pay-java-baidu/pom.xml | 2 +- pay-java-common/pom.xml | 2 +- .../pay/common/util/sign/SignUtils.java | 17 +-- pay-java-demo/pom.xml | 20 +-- .../demo/controller/UnionPayController.java | 2 +- .../demo/controller/WxV3PayController.java | 34 +++-- pay-java-fuiou/pom.xml | 2 +- pay-java-payoneer/pom.xml | 2 +- pay-java-paypal/pom.xml | 2 +- pay-java-union/pom.xml | 2 +- pay-java-web-support/pom.xml | 2 +- pay-java-wx-youdian/pom.xml | 2 +- pay-java-wx/pom.xml | 2 +- .../wx/v3/api/DefaultWxPayAssistService.java | 33 +++-- .../pay/wx/v3/api/WxPayConfigStorage.java | 85 ++++++++++--- .../egzosn/pay/wx/v3/api/WxPayService.java | 54 +++----- .../pay/wx/v3/bean/CertEnvironment.java | 23 ++-- .../pay/wx/v3/utils/AntCertificationUtil.java | 116 ++++++++++-------- pay-java-wx/src/test/java/PayTest.java | 34 ++++- pay-java-yiji/pom.xml | 2 +- pom.xml | 94 +++++++------- 23 files changed, 328 insertions(+), 227 deletions(-) diff --git a/pay-java-ali/pom.xml b/pay-java-ali/pom.xml index 9985ca2..a33b624 100644 --- a/pay-java-ali/pom.xml +++ b/pay-java-ali/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 pay-java-ali diff --git a/pay-java-ali/src/test/java/PayTest.java b/pay-java-ali/src/test/java/PayTest.java index 416ec15..9222848 100644 --- a/pay-java-ali/src/test/java/PayTest.java +++ b/pay-java-ali/src/test/java/PayTest.java @@ -28,7 +28,7 @@ public class PayTest { * */ private static void keyPublic(AliPayConfigStorage aliPayConfigStorage){ - aliPayConfigStorage.setKeyPublic("支付宝公钥"); + aliPayConfigStorage.setKeyPublic("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApTUBNm4Mf2K+PPWlluFUBhxu8ML3XgF7PoWHfLa470nTS3L5P9spfpFUbF4rjozBNblZ2QYWaskF92zSDegSvAzrgTMveHpv6+0G9uGgGLqObkPz3J8oQNioEL5Jtro2Zw7cVl+vpTIVWC9ChZE4acr1EDic4HJkWiA13OuyUx0Jl8wX9RXZPUp6nQ6LAz4FXGwfhy6zVveHvdkoeLxAo7ibcJh5eTjzDW0Ks4D32PwjU/uVIxeWAN4FybvF3wXOfl/RVYtbs9EZi63zlZI9h52Wj0hfFNcTNyGt/TBmYG1dRHRSkAGOGnza2ofBlV9y1PX9qL6O7Hoyu+BcTQRmCwIDAQAB"); } /** @@ -49,27 +49,28 @@ public class PayTest { public static void main(String[] args) { AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage(); - aliPayConfigStorage.setPid("合作者id"); - aliPayConfigStorage.setAppId("应用id"); +// aliPayConfigStorage.setPid("合作者id"); + aliPayConfigStorage.setAppId("2021005104613925"); //普通公钥方式与证书公钥方式为两者取其一的方式 keyPublic(aliPayConfigStorage); // certKeyPublic(aliPayConfigStorage); - aliPayConfigStorage.setKeyPrivate("应用私钥"); - aliPayConfigStorage.setNotifyUrl("异步回调地址"); - aliPayConfigStorage.setReturnUrl("同步回调地址"); - aliPayConfigStorage.setSignType("签名方式"); - aliPayConfigStorage.setSeller("收款账号"); + aliPayConfigStorage.setKeyPrivate("MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCocbFh28Ja+qhKXsSxkmu820LFE9rdVuJ1E7So/FcNxfqbHbGcd0iTOqZLy8gtw82BUDn+YJSrL3wpsWoKjL4n/LelMwjd3sYmOgx6hWrM6KBHFCSO2TDv4ZFQOEo8bHTotxQoVGFRrSpZ0VZlMe1BJvJdbgaZW9L02v9LOZfRtbR8QbPW2fzGoXLS/X0BVPCIm3W2BoI50RBHHGbW4rEx3iC93y8HM6efCbTYD3VwVFMAbYIcndrXomdQmkPnyIbtBMqvhzJCoDCwDHXJi2rhEQajpUlNVDtgiz9w12qaaaf+b/GChAdyGEBWilgaXI0DktJ21xxEhbvOvtDypMr5AgMBAAECggEAGP19HpKW/B5x906mCd46Q7OX7VsrvmjUgiAhTmzZkX6M1pSKNDdyOf2ajGY4VanWBFhdskKr69XIqvraS6Rj1dTlfgnbR+d0KFm2XjsLBEmC9eikH9lTLFOf1nHzeZFxqtD2maEjKxXw0ZCAK9VDaMYZcQkQy5HW82LGO2fZAVCgjnIC7HnbZIyTfRMRpnWGusEAFIqWGPos4L9N4G6nDtHQnY7G0JiSLb1X3g4bOFZFqyFQWqKWwY0b4TJmmiNHVY43o4EIS2kSRIGomjsDoHORSygit9jEsFtBMZB07JGHAjEeHNe7q3XsgR7AuK83gskDoHCUK1j+hK8p3u07MQKBgQDyx5q5xOhLnXTgAyFXlGYOVhb7izZp+tOl1CR73EL3ECu9oETHf0zQfGjImIeTt6ppn9iTCaqJk066zowVzCI83eCo6EaPHqVsFWEwiMXdg2O3LqQX/elWpAID6WQejTuRBUt+mtXKIA5Nd2VERLRvhwHKGW5FLHTr1ywVV6k2dQKBgQCxndYLQBQv2MqgniKwj+TSIQq8G6EvdCRBYJyyWgBKRbE+WZ+pFMDhIdnvqRXyj3jBMCmhD8QgAETkSrQqWuVPK+DUPu2MFzn+QAuiClvsN9zrplxf1ahv9m+MBcmk9wZy7C9eFF2UTrSrQTb8T52hhzCT2H5jTLGVLqLbrBFZ9QKBgQChaEka5qmV1AonAI3DPzsWnu/KrsQvc34QytiyrD6tKUgbWxk/FQhJt9ymOJoygDJA5O/E2fFSY+g81CNYPo4or060nTCD6FkMYa5q6RO7cKXz3INmG/5tBr78QMe6dCU9Bisp8eDe767ym8VsvMzFNRngdkXUoXjebwC088HhHQKBgQCuZDWT6D+p1ubkmz+eMjpOIskidtJlAFjUpCJWb03XnuPvPxonbkwPACi2SkNVXI8Ix9wn2o4LiZgaukp5R7Pcb02Zt4uPQALd405ItHkazqKn8TjDk8mE3OcbCVe6FB0N216Ktd5HzptPhoGRbC5uOYl1sFwv7U5zFk4q96A1vQKBgQDq6dK5t/BPQ6HQjb2Ys0CxWLefJn77zmyswGAfQ1VvZjcV9NSA5mVBVN3qU27oIcIkBIp+XE61lVPqRGzGxY8eZCdJPw5o0u9rGp/3mIS8WIZQ3Bkl+tkC5fS2bfwho9mJJJhvmFIddWqWMFCQRtk3TkwD0r2KqJ6pcQuyhipv0Q=="); + aliPayConfigStorage.setNotifyUrl("https://kgpg44675804.vicp.fun/pay/2"); + aliPayConfigStorage.setReturnUrl("https://kgpg44675804.vicp.fun/pay/2"); + aliPayConfigStorage.setSignType("RSA2"); +// aliPayConfigStorage.setSeller("收款账号"); aliPayConfigStorage.setInputCharset("utf-8"); //是否为测试账号,沙箱环境 - aliPayConfigStorage.setTest(true); +// aliPayConfigStorage.setTest(true); //支付服务 PayService service = new AliPayService(aliPayConfigStorage); //支付订单基础信息 PayOrder payOrder = new PayOrder("订单title", "摘要", BigDecimal.valueOf(0.01) , UUID.randomUUID().toString().replace("-", "")); /*-----------扫码付-------------------*/ payOrder.setTransactionType(AliTransactionType.SWEEPPAY); + String image = service.getQrPay(payOrder); //获取扫码付的二维码 - BufferedImage image = service.genQrPay(payOrder); +// BufferedImage image = service.genQrPay(payOrder); /*-----------/扫码付-------------------*/ /*-----------APP-------------------*/ diff --git a/pay-java-baidu/pom.xml b/pay-java-baidu/pom.xml index 650c6cc..e511144 100644 --- a/pay-java-baidu/pom.xml +++ b/pay-java-baidu/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 pay-java-baidu diff --git a/pay-java-common/pom.xml b/pay-java-common/pom.xml index 93de96e..d421454 100644 --- a/pay-java-common/pom.xml +++ b/pay-java-common/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 jar diff --git a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java index a73bab7..0c59cbf 100644 --- a/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java +++ b/pay-java-common/src/main/java/com/egzosn/pay/common/util/sign/SignUtils.java @@ -1,16 +1,15 @@ package com.egzosn.pay.common.util.sign; +import com.egzosn.pay.common.bean.SignType; +import com.egzosn.pay.common.util.sign.encrypt.HmacSha256; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + import java.security.Security; import java.util.Map; -import org.bouncycastle.jce.provider.BouncyCastleProvider; - import static com.egzosn.pay.common.util.sign.SignTextUtils.parameterText; -import com.egzosn.pay.common.bean.SignType; -import com.egzosn.pay.common.util.sign.encrypt.HmacSha256; - /** * 签名 工具 * @@ -197,12 +196,8 @@ public enum SignUtils implements SignType { * 初始化BC */ public static void initBc() { - String javaVersion = System.getProperty("java.version"); - if (javaVersion.contains("1.8") || javaVersion.startsWith("8")) { - if (null == Security.getProvider("BC")) { - Security.removeProvider("SunEC"); - Security.addProvider(new BouncyCastleProvider()); - } + if (null == Security.getProvider("BC")) { + Security.addProvider(new BouncyCastleProvider()); } } diff --git a/pay-java-demo/pom.xml b/pay-java-demo/pom.xml index dc143c4..7e88c40 100644 --- a/pay-java-demo/pom.xml +++ b/pay-java-demo/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 war @@ -24,39 +24,39 @@ com.egzosn pay-java-payoneer - ${pay.version} + ${revision} com.egzosn pay-java-wx - ${pay.version} + ${revision} com.egzosn pay-java-ali - ${pay.version} + ${revision} com.egzosn pay-java-wx-youdian - ${pay.version} + ${revision} com.egzosn pay-java-fuiou - ${pay.version} + ${revision} com.egzosn pay-java-paypal - ${pay.version} + ${revision} com.egzosn pay-java-union - ${pay.version} + ${revision} @@ -105,8 +105,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 8 + 8 UTF-8 diff --git a/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/UnionPayController.java b/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/UnionPayController.java index 46e1b4a..4a8ff59 100644 --- a/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/UnionPayController.java +++ b/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/UnionPayController.java @@ -38,7 +38,7 @@ import com.egzosn.pay.web.support.HttpRequestNoticeParams; * email egzosn@gmail.com * date 2016/11/18 0:25 */ -@RestController +//@RestController @RequestMapping("union") public class UnionPayController { diff --git a/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/WxV3PayController.java b/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/WxV3PayController.java index d538309..fd1887e 100644 --- a/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/WxV3PayController.java +++ b/pay-java-demo/src/main/java/com/egzosn/pay/demo/controller/WxV3PayController.java @@ -5,6 +5,8 @@ package com.egzosn.pay.demo.controller; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -17,7 +19,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.egzosn.pay.common.bean.AssistOrder; -import com.egzosn.pay.common.bean.CertStoreType; import com.egzosn.pay.common.bean.PayOrder; import com.egzosn.pay.common.bean.RefundOrder; import com.egzosn.pay.common.bean.RefundResult; @@ -49,25 +50,34 @@ public class WxV3PayController { private WxPayService service = null; + // @PostConstruct //没有证书的情况下注释掉,避免启动报错 public void init() { - WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage(); - wxPayConfigStorage.setAppId("wxc7b993ff15a9f26c"); - wxPayConfigStorage.setMchId("1602947765"); + com.egzosn.pay.wx.v3.api.WxPayConfigStorage wxPayConfigStorage = new com.egzosn.pay.wx.v3.api.WxPayConfigStorage(); + wxPayConfigStorage.setAppId("wx5ce9f1a2****"); + wxPayConfigStorage.setMchId("170330*****"); //V3密钥 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_2.shtml - wxPayConfigStorage.setV3ApiKey("9bd8f0e7af4841299d782406b7774f57"); - //验签、转账等接口使用,9月份开始不允许获取证书方式了,直接通过公钥字符来做, + wxPayConfigStorage.setV3ApiKey("KDBX2tbrKi9eWFEZ*****"); +// //验签、转账等接口使用,9月份开始不允许获取证书方式了,直接通过公钥字符来做或公钥证书 +// wxPayConfigStorage.setPlatformCertificate(Files.readString(Paths.get("wechatpay//wechatpay_72C2EF0EE5095C6D************.pem"))); +// wxPayConfigStorage.setPlatformSerialNumber("72C2EF0EE5095C6D************"); + //验签、转账等接口使用,9月份开始不允许获取证书方式了,直接通过公钥字符来做或公钥证书 wxPayConfigStorage.setKeyPublic("支付平台公钥(原为自动获取的证书)"); wxPayConfigStorage.setKeyPublicId("支付平台公钥ID"); - wxPayConfigStorage.setNotifyUrl("http://sailinmu.iok.la/wxV3/payBack.json"); - wxPayConfigStorage.setReturnUrl("http://sailinmu.iok.la/wxV3/payBack.json"); + + wxPayConfigStorage.setNotifyUrl("https://pay.egzosn.com/wxV3/payBack.json"); + wxPayConfigStorage.setReturnUrl("https://pay.egzosn.com/wxV3/payBack.json"); wxPayConfigStorage.setInputCharset("utf-8"); //使用证书时设置为true // wxPayConfigStorage.setCertSign(true); - //商户API证书 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml - wxPayConfigStorage.setApiClientKeyP12("http://pay.egzosn.com/yifenli_mall.p12"); - wxPayConfigStorage.setCertStoreType(CertStoreType.URL); - service = new WxPayService(wxPayConfigStorage); + /使用P12证书方式, 商户API证书 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml +// wxPayConfigStorage.setApiClientKeyP12("http://pay.egzosn.com/yifenli_mall.p12"); +// wxPayConfigStorage.setCertStoreType(CertStoreType.URL); + //使用pem证书方式 + wxPayConfigStorage.setKeyPrivate(Files.readString(Paths.get("wechatpay/apiclient_key.pem"))); + wxPayConfigStorage.setMerchantSerialNumber("2C1230A7BA8C7B197FC90852CCA****"); + + com.egzosn.pay.wx.v3.api.WxPayService service = new com.egzosn.pay.wx.v3.api.WxPayService(wxPayConfigStorage); //微信海外支付:东南亚 // service.setApiServerUrl("https://apihk.mch.weixin.qq.com"); //设置回调消息处理 diff --git a/pay-java-fuiou/pom.xml b/pay-java-fuiou/pom.xml index 107215b..a7be85e 100644 --- a/pay-java-fuiou/pom.xml +++ b/pay-java-fuiou/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 pay-java-fuiou diff --git a/pay-java-payoneer/pom.xml b/pay-java-payoneer/pom.xml index 7f208e3..d785d49 100644 --- a/pay-java-payoneer/pom.xml +++ b/pay-java-payoneer/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 pay-java-payoneer diff --git a/pay-java-paypal/pom.xml b/pay-java-paypal/pom.xml index 83a9066..1bca09f 100644 --- a/pay-java-paypal/pom.xml +++ b/pay-java-paypal/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 diff --git a/pay-java-union/pom.xml b/pay-java-union/pom.xml index 00721c6..2c7c131 100644 --- a/pay-java-union/pom.xml +++ b/pay-java-union/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 diff --git a/pay-java-web-support/pom.xml b/pay-java-web-support/pom.xml index 2ddceda..6ec235a 100644 --- a/pay-java-web-support/pom.xml +++ b/pay-java-web-support/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 jar diff --git a/pay-java-wx-youdian/pom.xml b/pay-java-wx-youdian/pom.xml index 5b78c0c..0477d8b 100644 --- a/pay-java-wx-youdian/pom.xml +++ b/pay-java-wx-youdian/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 pay-java-wx-youdian diff --git a/pay-java-wx/pom.xml b/pay-java-wx/pom.xml index b854962..0831b6d 100644 --- a/pay-java-wx/pom.xml +++ b/pay-java-wx/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 pay-java-wx diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/DefaultWxPayAssistService.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/DefaultWxPayAssistService.java index 54897ff..c268183 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/DefaultWxPayAssistService.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/DefaultWxPayAssistService.java @@ -1,17 +1,5 @@ package com.egzosn.pay.wx.v3.api; -import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; -import java.security.cert.Certificate; -import java.util.Map; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.entity.ContentType; -import org.apache.http.message.BasicHeader; - -import static org.apache.http.entity.ContentType.APPLICATION_JSON; - import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -30,6 +18,17 @@ import com.egzosn.pay.wx.bean.WxPayError; import com.egzosn.pay.wx.v3.bean.WxTransactionType; import com.egzosn.pay.wx.v3.utils.AntCertificationUtil; import com.egzosn.pay.wx.v3.utils.WxConst; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.message.BasicHeader; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.security.cert.Certificate; +import java.util.Map; + +import static org.apache.http.entity.ContentType.APPLICATION_JSON; /** * 默认的微信支付辅助服务 @@ -151,7 +150,7 @@ public class DefaultWxPayAssistService implements WxPayAssistService { //签名信息 String signText = StringUtils.joining("\n", method, canonicalUrl, String.valueOf(timestamp), nonceStr, body); String sign = wxPayService.createSign(signText, payConfigStorage.getInputCharset()); - String serialNumber = payConfigStorage.getCertEnvironment().getSerialNumber(); + String serialNumber = payConfigStorage.getCertEnvironment().getMerchantSerialNumber(); // 生成token String token = String.format(WxConst.TOKEN_PATTERN, payConfigStorage.getMchId(), nonceStr, timestamp, serialNumber, sign); HttpStringEntity entity = new HttpStringEntity(body, ContentType.APPLICATION_JSON); @@ -170,6 +169,14 @@ public class DefaultWxPayAssistService implements WxPayAssistService { */ @Override public void refreshCertificate() { + if (null != payConfigStorage.getCertEnvironment().getPublicKey()){ + return; + } + if (StringUtils.isNotEmpty(payConfigStorage.getPlatformCertificate()) && null == payConfigStorage.getCertEnvironment().getPublicKey()) { + AntCertificationUtil.loadCertificate(payConfigStorage.getPlatformSerialNumber(), new ByteArrayInputStream(payConfigStorage.getPlatformCertificate().getBytes(StandardCharsets.UTF_8))); + return; + } + JSONObject responseEntity = doExecute("", WxTransactionType.CERT); if (null == responseEntity) { diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayConfigStorage.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayConfigStorage.java index 1457d1b..800bf84 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayConfigStorage.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayConfigStorage.java @@ -1,16 +1,20 @@ package com.egzosn.pay.wx.v3.api; -import java.io.IOException; -import java.io.InputStream; - import com.egzosn.pay.common.api.BasePayConfigStorage; import com.egzosn.pay.common.bean.CertStoreType; import com.egzosn.pay.common.bean.result.PayException; import com.egzosn.pay.common.exception.PayErrorException; +import com.egzosn.pay.common.util.str.StringUtils; import com.egzosn.pay.wx.v3.bean.CertEnvironment; import com.egzosn.pay.wx.v3.utils.AntCertificationUtil; import com.egzosn.pay.wx.v3.utils.WxConst; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.cert.Certificate; + /** * 微信配置存储 * @@ -55,14 +59,26 @@ public class WxPayConfigStorage extends BasePayConfigStorage { * V2 Api密钥 */ private String apiKey; + /** + * 微信支付V3 Api密钥 + */ + private String v3ApiKey; /** * 商户API证书 * 包含商户的商户号、公司名称、公钥信息 * 详情 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml */ + @Deprecated private Object apiClientKeyP12; + + private String merchantSerialNumber; + + + private String platformCertificate; + private String platformSerialNumber; + /** * 证书存储类型 */ @@ -134,16 +150,20 @@ public class WxPayConfigStorage extends BasePayConfigStorage { addAttr("apiKey", apiKey); } - public void setV3ApiKey(String v3ApiKey) { - setKeyPrivate(v3ApiKey); - } - /** - * 为商户平台设置的密钥key - * - * @return 微信v3密钥 - */ public String getV3ApiKey() { - return getKeyPrivate(); + return v3ApiKey; + } + + public void setV3ApiKey(String v3ApiKey) { + this.v3ApiKey = v3ApiKey; + } + + public String getMerchantSerialNumber() { + return merchantSerialNumber; + } + + public void setMerchantSerialNumber(String merchantSerialNumber) { + this.merchantSerialNumber = merchantSerialNumber; } public void setAppId(String appId) { @@ -239,6 +259,22 @@ public class WxPayConfigStorage extends BasePayConfigStorage { return certEnvironment; } + public String getPlatformCertificate() { + return platformCertificate; + } + + public void setPlatformCertificate(String platformCertificate) { + this.platformCertificate = platformCertificate; + } + + public String getPlatformSerialNumber() { + return platformSerialNumber; + } + + public void setPlatformSerialNumber(String platformSerialNumber) { + this.platformSerialNumber = platformSerialNumber; + } + public void setCertEnvironment(CertEnvironment certEnvironment) { this.certEnvironment = certEnvironment; } @@ -250,12 +286,27 @@ public class WxPayConfigStorage extends BasePayConfigStorage { if (null != this.certEnvironment) { return; } - try (InputStream apiKeyCert = certStoreType.getInputStream(getApiClientKeyP12())) { - this.certEnvironment = AntCertificationUtil.initCertification(apiKeyCert, WxConst.CERT_ALIAS, getMchId()); - } - catch (IOException e) { - throw new PayErrorException(new PayException("读取证书异常", e.getMessage())); + + if (null != getApiClientKeyP12()) { + try (InputStream apiKeyCert = certStoreType.getInputStream(getApiClientKeyP12())) { + this.certEnvironment = AntCertificationUtil.initCertification(apiKeyCert, WxConst.CERT_ALIAS, getMchId()); + + } catch (IOException e) { + throw new PayErrorException(new PayException("读取证书异常", e.getMessage())); + } + } else if (null != getKeyPrivate()) { + + this.certEnvironment = AntCertificationUtil.initCertification(getKeyPrivate(), getMerchantSerialNumber(), getKeyPublic(), getKeyPublicId()); + if (StringUtils.isNotEmpty(getPlatformCertificate())) { + Certificate certificate = AntCertificationUtil.loadCertificate(getPlatformSerialNumber(), new ByteArrayInputStream(getPlatformCertificate().getBytes(StandardCharsets.UTF_8))); + this.certEnvironment.setPlatformSerialNumber(getPlatformSerialNumber()); + this.certEnvironment.setPublicKey(certificate.getPublicKey()); + + } + } + + } public boolean isPartner() { diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java index 505f41f..a972986 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/api/WxPayService.java @@ -1,46 +1,10 @@ package com.egzosn.pay.wx.v3.api; -import java.io.IOException; -import java.io.InputStream; -import java.security.GeneralSecurityException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.apache.http.HttpEntity; -import org.apache.http.message.BasicHeader; - -import static com.egzosn.pay.wx.api.WxConst.OUT_TRADE_NO; -import static com.egzosn.pay.wx.api.WxConst.SANDBOXNEW; -import static com.egzosn.pay.wx.v3.utils.WxConst.FAILURE; - import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.egzosn.pay.common.api.BasePayService; import com.egzosn.pay.common.api.TransferService; -import com.egzosn.pay.common.bean.AssistOrder; -import com.egzosn.pay.common.bean.BillType; -import com.egzosn.pay.common.bean.CurType; -import com.egzosn.pay.common.bean.MethodType; -import com.egzosn.pay.common.bean.NoticeParams; -import com.egzosn.pay.common.bean.NoticeRequest; -import com.egzosn.pay.common.bean.OrderParaStructure; -import com.egzosn.pay.common.bean.PayMessage; -import com.egzosn.pay.common.bean.PayOrder; -import com.egzosn.pay.common.bean.PayOutMessage; -import com.egzosn.pay.common.bean.RefundOrder; -import com.egzosn.pay.common.bean.RefundResult; -import com.egzosn.pay.common.bean.TransactionType; -import com.egzosn.pay.common.bean.TransferOrder; +import com.egzosn.pay.common.bean.*; import com.egzosn.pay.common.bean.result.PayException; import com.egzosn.pay.common.exception.PayErrorException; import com.egzosn.pay.common.http.HttpConfigStorage; @@ -70,6 +34,21 @@ import com.egzosn.pay.wx.v3.bean.response.WxRefundResult; import com.egzosn.pay.wx.v3.bean.transfer.TransferDetail; import com.egzosn.pay.wx.v3.utils.AntCertificationUtil; import com.egzosn.pay.wx.v3.utils.WxConst; +import org.apache.http.HttpEntity; +import org.apache.http.message.BasicHeader; + +import java.io.IOException; +import java.io.InputStream; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.util.*; +import java.util.stream.Collectors; + +import static com.egzosn.pay.wx.api.WxConst.OUT_TRADE_NO; +import static com.egzosn.pay.wx.api.WxConst.SANDBOXNEW; +import static com.egzosn.pay.wx.v3.utils.WxConst.FAILURE; /** * 微信支付服务 @@ -133,6 +112,7 @@ public class WxPayService extends BasePayService implements if (null == assistService) { assistService = new DefaultWxPayAssistService(this); } + if (StringUtils.isEmpty(payConfigStorage.getKeyPublic())) { //在这预先进行初始化 assistService.refreshCertificate(); diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/CertEnvironment.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/CertEnvironment.java index 4b226a3..347423a 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/CertEnvironment.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/bean/CertEnvironment.java @@ -26,7 +26,7 @@ public class CertEnvironment { /** * 公钥序列 */ - private String serialNumber; + private String merchantSerialNumber; /** * 微信平台证书序列号 @@ -37,10 +37,17 @@ public class CertEnvironment { public CertEnvironment() { } - public CertEnvironment(PrivateKey privateKey, PublicKey publicKey, String serialNumber) { + public CertEnvironment(PrivateKey privateKey, PublicKey publicKey, String merchantSerialNumber) { this.privateKey = privateKey; this.publicKey = publicKey; - this.serialNumber = serialNumber; + this.merchantSerialNumber = merchantSerialNumber; + } + + public CertEnvironment(PrivateKey privateKey, String merchantSerialNumber, PublicKey publicKey, String publicSerialNumber) { + this.privateKey = privateKey; + this.publicKey = publicKey; + this.merchantSerialNumber = merchantSerialNumber; + this.platformSerialNumber = publicSerialNumber; } public PrivateKey getPrivateKey() { @@ -59,17 +66,17 @@ public class CertEnvironment { this.publicKey = publicKey; } - public String getSerialNumber() { - return serialNumber; + public String getMerchantSerialNumber() { + return merchantSerialNumber; } - public void setSerialNumber(String serialNumber) { - this.serialNumber = serialNumber; + public void setMerchantSerialNumber(String merchantSerialNumber) { + this.merchantSerialNumber = merchantSerialNumber; } public String getPlatformSerialNumber() { if (StringUtils.isEmpty(platformSerialNumber)) { - setPlatformSerialNumber(serialNumber); + setPlatformSerialNumber(merchantSerialNumber); } return platformSerialNumber; } diff --git a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/AntCertificationUtil.java b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/AntCertificationUtil.java index 5e6a58f..a7afe5d 100644 --- a/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/AntCertificationUtil.java +++ b/pay-java-wx/src/main/java/com/egzosn/pay/wx/v3/utils/AntCertificationUtil.java @@ -1,16 +1,22 @@ package com.egzosn.pay.wx.v3.utils; +import com.egzosn.pay.common.exception.PayErrorException; +import com.egzosn.pay.common.util.sign.SignUtils; +import com.egzosn.pay.common.util.sign.encrypt.Base64; +import com.egzosn.pay.common.util.sign.encrypt.RSA; +import com.egzosn.pay.common.util.str.StringUtils; +import com.egzosn.pay.wx.bean.WxPayError; +import com.egzosn.pay.wx.v3.bean.CertEnvironment; + +import javax.crypto.Cipher; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.management.openmbean.InvalidKeyException; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.Security; +import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -18,17 +24,6 @@ import java.security.cert.X509Certificate; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import javax.crypto.Cipher; -import javax.crypto.spec.GCMParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.management.openmbean.InvalidKeyException; - -import com.egzosn.pay.common.exception.PayErrorException; -import com.egzosn.pay.common.util.sign.SignUtils; -import com.egzosn.pay.common.util.sign.encrypt.Base64; -import com.egzosn.pay.wx.bean.WxPayError; -import com.egzosn.pay.wx.v3.bean.CertEnvironment; - /** * 证书文件可信校验 * @@ -46,29 +41,31 @@ public final class AntCertificationUtil { private AntCertificationUtil() { } - private static final KeyStore PKCS12_KEY_STORE; + private static KeyStore PKCS12_KEY_STORE; - private static final CertificateFactory CERTIFICATE_FACTORY; + private static CertificateFactory CERTIFICATE_FACTORY; static { - String javaVersion = System.getProperty("java.version"); - if (javaVersion.contains("1.8") || javaVersion.startsWith("8")) { + init(); + } + + public synchronized static void init() { + if (null == PKCS12_KEY_STORE && null == CERTIFICATE_FACTORY) { Security.setProperty("crypto.policy", "unlimited"); - } - SignUtils.initBc(); - try { - PKCS12_KEY_STORE = KeyStore.getInstance("PKCS12"); - } - catch (KeyStoreException e) { - throw new PayErrorException(new WxPayError(WxConst.FAILURE, " keystore 初始化失败"), e); + SignUtils.initBc(); + try { + PKCS12_KEY_STORE = KeyStore.getInstance("PKCS12"); + } catch (KeyStoreException e) { + throw new PayErrorException(new WxPayError(WxConst.FAILURE, " keystore 初始化失败"), e); + } + + try { + CERTIFICATE_FACTORY = CertificateFactory.getInstance("X509", WxConst.BC_PROVIDER); + } catch (NoSuchProviderException | CertificateException e) { + throw new PayErrorException(new WxPayError(WxConst.FAILURE, " keystore 初始化失败"), e); + } } - try { - CERTIFICATE_FACTORY = CertificateFactory.getInstance("X509", WxConst.BC_PROVIDER); - } - catch (NoSuchProviderException | CertificateException e) { - throw new PayErrorException(new WxPayError(WxConst.FAILURE, " keystore 初始化失败"), e); - } } @@ -85,8 +82,7 @@ public final class AntCertificationUtil { Certificate certificate = CERTIFICATE_FACTORY.generateCertificate(certificateStream); CERTIFICATE_MAP.put(serialNo, certificate); return certificate; - } - catch (CertificateException e) { + } catch (CertificateException e) { throw new PayErrorException(new WxPayError(WxConst.FAILURE, " 在生成微信v3证书时发生错误,原因是" + e.getMessage()), e); } @@ -103,6 +99,36 @@ public final class AntCertificationUtil { } + /** + * 初始化证书信息 + * + * @param privateKey 商户API私钥 + * @param merchantSerialNumber 商户证书序列号 + * @param publicKey 商户API证书公钥 + * @param publicKeyId 商户API证书公钥ID + * @return 证书信息集合 + */ + public static CertEnvironment initCertification(String privateKey, String merchantSerialNumber, String publicKey, String publicKeyId) { + + try { + + privateKey = privateKey.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", ""); + PrivateKey privateKeyObj = RSA.getPrivateKey(privateKey); + PublicKey publicKeyObj = null; + if (StringUtils.isNotEmpty(publicKey)) { + publicKey = publicKey.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").replaceAll("\\s+", ""); + publicKeyObj = RSA.getPublicKey(publicKey); + } + + return new CertEnvironment(privateKeyObj, merchantSerialNumber, publicKeyObj, publicKeyId); + } catch (GeneralSecurityException e) { + throw new PayErrorException(new WxPayError(WxConst.FAILURE, "获取公私钥失败"), e); + } catch (IOException e) { + throw new PayErrorException(new WxPayError(WxConst.FAILURE, "私钥证书流加载失败"), e); + } + + } + /** * 获取公私钥. * @@ -112,7 +138,6 @@ public final class AntCertificationUtil { * @return 证书信息集合 */ public static CertEnvironment initCertification(InputStream keyCertStream, String keyAlias, String keyPass) { - char[] pem = keyPass.toCharArray(); try { PKCS12_KEY_STORE.load(keyCertStream, pem); @@ -122,14 +147,11 @@ public final class AntCertificationUtil { PublicKey publicKey = certificate.getPublicKey(); PrivateKey privateKey = (PrivateKey) PKCS12_KEY_STORE.getKey(keyAlias, pem); return new CertEnvironment(privateKey, publicKey, serialNumber); - } - catch (InvalidKeyException e) { + } catch (InvalidKeyException e) { throw new PayErrorException(new WxPayError(WxConst.FAILURE, "获取公私钥失败, 解决方式:替换jre包:local_policy.jar,US_export_policy.jar"), e); - } - catch (GeneralSecurityException e) { + } catch (GeneralSecurityException e) { throw new PayErrorException(new WxPayError(WxConst.FAILURE, "获取公私钥失败"), e); - } - catch (IOException e) { + } catch (IOException e) { throw new PayErrorException(new WxPayError(WxConst.FAILURE, "私钥证书流加载失败"), e); } @@ -156,8 +178,7 @@ public final class AntCertificationUtil { cipher.updateAAD(associatedData.getBytes(Charset.forName(characterEncoding))); byte[] bytes = cipher.doFinal(Base64.decode(cipherText)); return new String(bytes, Charset.forName(characterEncoding)); - } - catch (GeneralSecurityException e) { + } catch (GeneralSecurityException e) { throw new PayErrorException(new WxPayError(WxConst.FAILURE, e.getMessage()), e); } } @@ -189,8 +210,7 @@ public final class AntCertificationUtil { byte[] cipherData = cipher.doFinal(data); return Base64.encode(cipherData); - } - catch (GeneralSecurityException e) { + } catch (GeneralSecurityException e) { throw new PayErrorException(new WxPayError(WxConst.FAILURE, e.getMessage()), e); } } diff --git a/pay-java-wx/src/test/java/PayTest.java b/pay-java-wx/src/test/java/PayTest.java index 4b42a60..d0e7013 100644 --- a/pay-java-wx/src/test/java/PayTest.java +++ b/pay-java-wx/src/test/java/PayTest.java @@ -1,4 +1,3 @@ - import com.egzosn.pay.common.bean.CertStoreType; import com.egzosn.pay.common.bean.MethodType; import com.egzosn.pay.common.bean.PayOrder; @@ -10,7 +9,10 @@ import com.egzosn.pay.wx.bean.WxSendredpackType; import com.egzosn.pay.wx.bean.WxTransactionType; import java.awt.image.BufferedImage; +import java.io.IOException; import java.math.BigDecimal; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Map; import java.util.UUID; @@ -24,7 +26,35 @@ import java.util.UUID; */ public class PayTest { - public static void main(String[] args) { + public static void main(String[] args) throws IOException { + com.egzosn.pay.wx.v3.api.WxPayConfigStorage wxPayConfigStorage = new com.egzosn.pay.wx.v3.api.WxPayConfigStorage(); + wxPayConfigStorage.setAppId("wx5ce9f1a2****"); + wxPayConfigStorage.setMchId("170330*****"); + //V3密钥 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_2.shtml + wxPayConfigStorage.setV3ApiKey("KDBX2tbrKi9eWFEZ*****"); + //验签、转账等接口使用,9月份开始不允许获取证书方式了,直接通过公钥字符来做, + wxPayConfigStorage.setPlatformCertificate(Files.readString(Paths.get("wechatpay//wechatpay_72C2EF0EE5095C6D************.pem"))); + wxPayConfigStorage.setPlatformSerialNumber("72C2EF0EE5095C6D************"); + wxPayConfigStorage.setNotifyUrl("https://pay.egzosn.com/wxV3/payBack.json"); + wxPayConfigStorage.setReturnUrl("https://pay.egzosn.com/wxV3/payBack.json"); + wxPayConfigStorage.setInputCharset("utf-8"); + //使用证书时设置为true +// wxPayConfigStorage.setCertSign(true); + //商户API证书 https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay3_1.shtml +// wxPayConfigStorage.setApiClientKeyP12("http://pay.egzosn.com/yifenli_mall.p12"); +// wxPayConfigStorage.setCertStoreType(CertStoreType.URL); + wxPayConfigStorage.setKeyPrivate(Files.readString(Paths.get("wechatpay/apiclient_key.pem"))); + wxPayConfigStorage.setMerchantSerialNumber("2C1230A7BA8C7B197FC90852CCA****"); + + com.egzosn.pay.wx.v3.api.WxPayService service = new com.egzosn.pay.wx.v3.api.WxPayService(wxPayConfigStorage); + //微信海外支付:东南亚 +// service.setApiServerUrl("https://apihk.mch.weixin.qq.com"); + String qrPay = service.getQrPay(new PayOrder("测试订单", "测试商品", BigDecimal.valueOf(0.01), "2018091011111111")); + //设置回调消息处理 + //TODO {@link com.egzosn.pay.demo.controller.WxPayController#payBack} + System.out.println(); + } + public static void mainV2() { WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage(); wxPayConfigStorage.setAppId("公众账号ID"); diff --git a/pay-java-yiji/pom.xml b/pay-java-yiji/pom.xml index bdf6cae..81ed1c7 100644 --- a/pay-java-yiji/pom.xml +++ b/pay-java-yiji/pom.xml @@ -5,7 +5,7 @@ pay-java-parent com.egzosn - 2.14.8 + ${revision} 4.0.0 diff --git a/pom.xml b/pom.xml index 49afca8..df5bfd4 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.egzosn pay-java-parent pom - 2.14.8 + ${revision} Pay Java - Parent Pay Java Parent @@ -64,13 +64,19 @@ - 2.14.8 + 2.14.9 4.5.4 1.2.17 1.2.83 3.3.1 4.0.1 1.59 + 17 + 17 + 17 + UTF-8 + UTF-8 + 1.1.0 @@ -80,12 +86,12 @@ com.egzosn pay-java-common - ${pay.version} + ${revision} com.egzosn pay-java-web-support - ${pay.version} + ${revision} @@ -143,19 +149,48 @@ + org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 - utf-8 + + + -parameters + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} - + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + - + local @@ -167,36 +202,17 @@ proc - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.3 - true - - ossrh - https://oss.sonatype.org/ - false - - + org.apache.maven.plugins maven-release-plugin - 2.5.1 - - false - false - release - deploy - - org.apache.maven.plugins + true maven-javadoc-plugin - 2.10.3 attach-javadocs - install jar @@ -204,33 +220,17 @@ - org.apache.maven.plugins + true maven-source-plugin - 3.1.0 attach-sources - install jar-no-fork - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - install - - sign - - - -