From 66a9966e6ca1a13ad51e5b24ffd3f09d580fc393 Mon Sep 17 00:00:00 2001 From: Menjoe <1030009014@qq.com> Date: Mon, 12 Apr 2021 22:04:20 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=8E=A5=E9=80=9A=E7=99=BE=E5=BA=A6?= =?UTF-8?q?=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pay/baidu/api/BaiduPayConfigStorage.java | 39 ++--- .../egzosn/pay/baidu/api/BaiduPayService.java | 138 ++++++++++++++++-- .../pay/baidu/api/BaiduPayServiceTest.java | 2 +- 3 files changed, 149 insertions(+), 30 deletions(-) diff --git a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayConfigStorage.java b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayConfigStorage.java index 7786b80..61ee1cd 100644 --- a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayConfigStorage.java +++ b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayConfigStorage.java @@ -3,13 +3,23 @@ package com.egzosn.pay.baidu.api; import com.egzosn.pay.common.api.BasePayConfigStorage; public class BaiduPayConfigStorage extends BasePayConfigStorage { - private String appId; + + private String appid; + private String dealId; + /** + * 支付平台公钥(签名校验使用) + */ + private String keyPublic; @Override - @Deprecated public String getAppid() { - return this.appId; + return this.appid; + } + + @Override + public String getAppId() { + return this.appid; } @Override @@ -17,9 +27,10 @@ public class BaiduPayConfigStorage extends BasePayConfigStorage { return getDealId(); } + //使用json序列化的时候会报错,所以不要直接抛出异常 @Override public String getSeller() { - throw new UnsupportedOperationException("不支持"); + return getDealId(); } public String getDealId() { @@ -31,33 +42,25 @@ public class BaiduPayConfigStorage extends BasePayConfigStorage { } public String getAppKey() { - return this.getKeyPrivate(); + return this.appid; } public void setAppKey(String appKey) { - setKeyPrivate(appKey); + this.setAppid(appKey); } @Override public String getKeyPublic() { - return super.getKeyPrivate(); + return keyPublic; } @Override public void setKeyPublic(String keyPublic) { - super.setKeyPublic(keyPublic); - } - - public void setAppid(String appId) { - this.appId = appId; + this.keyPublic = keyPublic; } - @Override - public String getAppId() { - return appId; + public void setAppid(String appid) { + this.appid = appid; } - public void setAppId(String appId) { - this.appId = appId; - } } diff --git a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java index a1e3267..e234257 100644 --- a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java +++ b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java @@ -1,9 +1,13 @@ package com.egzosn.pay.baidu.api; +import java.io.UnsupportedEncodingException; import java.math.BigDecimal; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; +import java.net.URLEncoder; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -51,6 +55,13 @@ public class BaiduPayService extends BasePayService { public static final String RESPONSE_STATUS = "status"; + private static final String CHARSET = "UTF-8"; + private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; + private static final String SIGN_TYPE_RSA = "RSA"; + private static final String SIGN_KEY = "rsaSign"; + public static final String PAY_MONEY = "payMoney"; + + public BaiduPayService(BaiduPayConfigStorage payConfigStorage) { super(payConfigStorage); } @@ -68,12 +79,103 @@ public class BaiduPayService extends BasePayService { */ @Override public boolean verify(Map params) { - if (!RESPONSE_SUCCESS.equals(params.get(RESPONSE_STATUS))) { + if (!RESPONSE_SUCCESS.equals(params.get(RESPONSE_STATUS)) && !RESPONSE_SUCCESS.toString().equals(params.get(RESPONSE_STATUS))) { return false; } - return signVerify(params, String.valueOf(params.get(RSA_SIGN))); + LOG.info("开始验证回调签名参数:" + params); + try { + boolean checkSign = this.checkReturnSign(params, payConfigStorage.getKeyPublic(), (String) params.get(RSA_SIGN)); + return checkSign; + } catch (Exception e) { + LOG.info("验签失败", e); + } + return false; + } + + public boolean checkReturnSign(Map params, String publicKey, String rsaSign) { + try { + String content = signContent(params); + Signature signature = Signature.getInstance(SIGN_ALGORITHMS); + signature.initVerify(this.getPublicKeyX509(publicKey)); + signature.update(content.getBytes(CHARSET)); + boolean verify = signature.verify(Base64.getDecoder().decode(rsaSign.getBytes(CHARSET))); + LOG.info("使用公钥进行验签: " + verify); + return verify; + } catch (Exception e) { + LOG.info("使用公钥进行验签出错, 返回false", e); + } + return false; + } + + + /** + * 将公钥字符串进行Base64 decode之后,生成X509标准公钥 + * + * @param publicKey 公钥原始字符串 + * + * @return X509标准公钥 + * + * @throws InvalidKeySpecException + * @throws NoSuchAlgorithmException + */ + private static PublicKey getPublicKeyX509(String publicKey) throws InvalidKeySpecException, + NoSuchAlgorithmException, UnsupportedEncodingException { + if (StringUtils.isEmpty(publicKey)) { + return null; + } + KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA); + byte[] decodedKey = Base64.getDecoder().decode(publicKey.getBytes(CHARSET)); + return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); } + /** + * 对输入参数进行key过滤排序和字符串拼接 + * + * @param params 待签名参数集合 + * + * @return 待签名内容 + * + * @throws UnsupportedEncodingException + */ + private String signContent(Map params) throws UnsupportedEncodingException { + Map sortedParams = new TreeMap<>(Comparator.naturalOrder()); + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + if (legalKey(key)) { + String value = + entry.getValue() == null ? null : URLEncoder.encode(entry.getValue().toString(), CHARSET); + sortedParams.put(key, value); + } + } + + StringBuilder builder = new StringBuilder(); + if (sortedParams != null && sortedParams.size() > 1) { + for (Map.Entry entry : sortedParams.entrySet()) { + if (StringUtils.equals(entry.getKey(), RSA_SIGN)) continue; + builder.append(entry.getKey()); + builder.append("="); + builder.append(entry.getValue()); + builder.append("&"); + } + builder.deleteCharAt(builder.length() - 1); + } + LOG.info("验签字符串:\n" + builder); + return builder.toString(); + } + + /** + * 有效的待签名参数key值 + * 非空、且非签名字段 + * + * @param key 待签名参数key值 + * + * @return true | false + */ + private static boolean legalKey(String key) { + return StringUtils.isNotBlank(key) && !SIGN_KEY.equalsIgnoreCase(key); + } + + /** * 验证签名 * @@ -97,8 +199,9 @@ public class BaiduPayService extends BasePayService { */ @Override public Map orderInfo(PayOrder order) { - Map params = getUseOrderInfoParams(order); - String rsaSign = getRsaSign(params, RSA_SIGN); + LOG.info("百度支付配置:" + JSON.toJSONString(payConfigStorage)); + Map params = this.getUseOrderInfoParams(order); + String rsaSign = this.getRsaSign(params, RSA_SIGN); params.put(RSA_SIGN, rsaSign); return params; } @@ -128,12 +231,15 @@ public class BaiduPayService extends BasePayService { String appKey = payConfigStorage.getAppKey(); String dealId = payConfigStorage.getDealId(); result.put(APP_KEY, appKey); - result.put(TP_ORDER_ID, payOrder.getTradeNo()); result.put(DEAL_ID, dealId); + result.put(TOTAL_AMOUNT, String.valueOf(Util.conversionCentAmount(order.getPrice()))); + result.put(TP_ORDER_ID, payOrder.getOutTradeNo()); + result.put(DEAL_TITLE, payOrder.getSubject()); result.put(SIGN_FIELDS_RANGE, payOrder.getSignFieldsRange()); result.put(BIZ_INFO, JSON.toJSONString(payOrder.getBizInfo())); - result.put(TOTAL_AMOUNT, String.valueOf(Util.conversionAmount(order.getPrice()))); + + LOG.info("百度支付 getUseOrderInfoParams:" + JSON.toJSONString(result)); return result; } @@ -489,7 +595,17 @@ public class BaiduPayService extends BasePayService { * @return 签名结果 */ private String getRsaSign(Map params, String... ignoreKeys) { - String waitSignVal = SignUtils.parameterText(params, "&", false, ignoreKeys); - return SignUtils.valueOf(payConfigStorage.getSignType()).createSign(waitSignVal, payConfigStorage.getKeyPrivate(), payConfigStorage.getInputCharset()); + Map result = new HashMap<>(); + String appKey = payConfigStorage.getAppKey(); + String dealId = payConfigStorage.getDealId(); + result.put(APP_KEY, appKey); + result.put(DEAL_ID, dealId); + result.put(TOTAL_AMOUNT, params.get(TOTAL_AMOUNT)); + result.put(TP_ORDER_ID, params.get(TP_ORDER_ID)); + + LOG.info("百度支付签名参数:" + JSON.toJSONString(result)); + + String waitSignVal = SignUtils.parameterText(result, "&", false, ignoreKeys); + return SignUtils.RSA.createSign(waitSignVal, payConfigStorage.getKeyPrivate(), payConfigStorage.getInputCharset()); } } diff --git a/pay-java-baidu/src/test/java/com/egzosn/pay/baidu/api/BaiduPayServiceTest.java b/pay-java-baidu/src/test/java/com/egzosn/pay/baidu/api/BaiduPayServiceTest.java index 9cb7434..6f9b5c2 100644 --- a/pay-java-baidu/src/test/java/com/egzosn/pay/baidu/api/BaiduPayServiceTest.java +++ b/pay-java-baidu/src/test/java/com/egzosn/pay/baidu/api/BaiduPayServiceTest.java @@ -13,7 +13,7 @@ public class BaiduPayServiceTest { @Test public void orderInfo() { BaiduPayConfigStorage configStorage = new BaiduPayConfigStorage(); - configStorage.setAppId("APP ID"); + configStorage.setAppid("APP ID"); configStorage.setAppKey("APP KEY"); configStorage.setDealId("DEAL ID"); configStorage.setKeyPublic("KEY PUBLIC"); -- Gitee From 0f24b22a325ffa2bb51f74f967f6625db9f532a7 Mon Sep 17 00:00:00 2001 From: "menjoe.zhou@islide.cc" Date: Wed, 14 Apr 2021 18:34:58 +0800 Subject: [PATCH 2/3] =?UTF-8?q?1.=20=E6=8E=92=E9=99=A41.8=E7=89=B9?= =?UTF-8?q?=E6=80=A7=202.=20=E6=9B=BF=E6=8D=A2base64=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/egzosn/pay/baidu/api/BaiduPayService.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java index e234257..8275398 100644 --- a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java +++ b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java @@ -5,9 +5,9 @@ import java.math.BigDecimal; import java.net.URLEncoder; import java.security.*; import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.*; +import com.egzosn.pay.common.util.sign.encrypt.Base64; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; @@ -98,7 +98,7 @@ public class BaiduPayService extends BasePayService { Signature signature = Signature.getInstance(SIGN_ALGORITHMS); signature.initVerify(this.getPublicKeyX509(publicKey)); signature.update(content.getBytes(CHARSET)); - boolean verify = signature.verify(Base64.getDecoder().decode(rsaSign.getBytes(CHARSET))); + boolean verify = signature.verify(Base64.decode(rsaSign)); LOG.info("使用公钥进行验签: " + verify); return verify; } catch (Exception e) { @@ -119,12 +119,12 @@ public class BaiduPayService extends BasePayService { * @throws NoSuchAlgorithmException */ private static PublicKey getPublicKeyX509(String publicKey) throws InvalidKeySpecException, - NoSuchAlgorithmException, UnsupportedEncodingException { + NoSuchAlgorithmException { if (StringUtils.isEmpty(publicKey)) { return null; } KeyFactory keyFactory = KeyFactory.getInstance(SIGN_TYPE_RSA); - byte[] decodedKey = Base64.getDecoder().decode(publicKey.getBytes(CHARSET)); + byte[] decodedKey = Base64.decode(publicKey); return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); } @@ -138,7 +138,12 @@ public class BaiduPayService extends BasePayService { * @throws UnsupportedEncodingException */ private String signContent(Map params) throws UnsupportedEncodingException { - Map sortedParams = new TreeMap<>(Comparator.naturalOrder()); + Map sortedParams = new TreeMap<>(new Comparator() { + @Override + public int compare(String o1, String o2) { + return o1.compareTo(o2); + } + }); for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); if (legalKey(key)) { -- Gitee From dfc55e271aafe3dd6827c97f6bc786c639143712 Mon Sep 17 00:00:00 2001 From: "menjoe.zhou@islide.cc" Date: Thu, 15 Apr 2021 14:17:12 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E4=B8=8D=E5=BF=85?= =?UTF-8?q?=E8=A6=81=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java index 8275398..3845a11 100644 --- a/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java +++ b/pay-java-baidu/src/main/java/com/egzosn/pay/baidu/api/BaiduPayService.java @@ -59,7 +59,6 @@ public class BaiduPayService extends BasePayService { private static final String SIGN_ALGORITHMS = "SHA1WithRSA"; private static final String SIGN_TYPE_RSA = "RSA"; private static final String SIGN_KEY = "rsaSign"; - public static final String PAY_MONEY = "payMoney"; public BaiduPayService(BaiduPayConfigStorage payConfigStorage) { -- Gitee