diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/LakalaController.java b/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/LakalaController.java index ab03ed37..78677a63 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/LakalaController.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/controller/mobile/LakalaController.java @@ -19,6 +19,7 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.util.Base64Utils; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import java.io.IOException; @Api(tags = "拉卡拉相关接口 - 前端控制器") @@ -44,8 +45,8 @@ public class LakalaController extends BaseControllerImpl { @ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调") @RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST) - public JSONObject ledgerApplyLedgerMerNotify(@RequestBody JSONObject paramsJSON) { - return lakalaPayService.applyLedgerMerNotify(paramsJSON); + public JSONObject ledgerApplyLedgerMerNotify(HttpServletRequest request) { + return lakalaPayService.applyLedgerMerNotify(request); } @ApiOperation(value = "分账接收方创建申请", notes = "分账接收方创建申请") @@ -62,7 +63,7 @@ public class LakalaController extends BaseControllerImpl { @ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知") @RequestMapping(value = "/ledger/applyBindNotify", method = RequestMethod.POST) - public JSONObject applyBindNotify(@RequestBody JSONObject paramsJSON) { - return lakalaPayService.applyLedgerMerReceiverBindNotify(paramsJSON); + public JSONObject applyBindNotify(HttpServletRequest request) { + return lakalaPayService.applyLedgerMerReceiverBindNotify(request); } } diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java index 9e8798f7..738bc79c 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java @@ -100,10 +100,10 @@ public interface LakalaPayService { * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 * - * @param paramsJSON + * @param request * @return */ - JSONObject applyLedgerMerNotify(JSONObject paramsJSON); + JSONObject applyLedgerMerNotify(HttpServletRequest request); /** * 分账接收方创建申请 @@ -129,10 +129,10 @@ public interface LakalaPayService { * 分账关系绑定申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 * - * @param paramsJSON + * @param request * @return */ - JSONObject applyLedgerMerReceiverBindNotify(JSONObject paramsJSON); + JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request); } diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java index 27da196e..8f811241 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java @@ -65,6 +65,8 @@ public class LakalaPayServiceImpl implements LakalaPayService { private String priKeyPath; //商户私钥信息地址 @Value("${lakala.lkl_platform_cer_path}") private String lklCerPath; //拉卡拉支付平台证书地址 + @Value("${lakala.api_cert_path}") + private String apiCertPath; @Value("${lakala.lkl_platform_cer_path}") private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签) @Value("${lakala.org_code}") @@ -465,12 +467,21 @@ public class LakalaPayServiceImpl implements LakalaPayService { * 商户分账业务开通申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 * - * @param paramsJSON + * @param request * @return */ @Override - public JSONObject applyLedgerMerNotify(JSONObject paramsJSON) { - // TODO 验签 + public JSONObject applyLedgerMerNotify(HttpServletRequest request) { + // 验签 + String authorization = request.getHeader("Authorization"); + String requestBody = LakalaUtil.getBody(request); + + boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); + if (!checkSuccess) { + return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + } + + JSONObject paramsJSON = JSONUtil.parseObj(requestBody); JSONObject respData = new JSONObject(); respData.put("retCode", "OP90003"); @@ -668,12 +679,23 @@ public class LakalaPayServiceImpl implements LakalaPayService { * 分账关系绑定申请回调 * 参考:https://o.lakala.com/#/home/document/detail?id=379 * - * @param paramsJSON + * @param request * @return */ @Override - public JSONObject applyLedgerMerReceiverBindNotify(JSONObject paramsJSON) { - // TODO 验签 + public JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request) { + // 验签 + String authorization = request.getHeader("Authorization"); + String requestBody = LakalaUtil.getBody(request); + + boolean checkSuccess = LakalaUtil.verify(authorization, requestBody, lklNotifyCerPath); + if (!checkSuccess) { + return JSONUtil.createObj().set("retCode", "OP90002").set("retMsg", "验签失败!"); + } + +// String requestBody = LakalaUtil.getBody(request); + + JSONObject paramsJSON = JSONUtil.parseObj(requestBody); JSONObject respData = new JSONObject(); respData.put("retCode", "OP90003"); respData.put("retMsg", "响应处理失败!"); diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java b/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java index 34378e44..0347ebb3 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/utils/LakalaUtil.java @@ -8,16 +8,15 @@ package com.suisung.mall.pay.utils; +import cn.hutool.core.util.StrUtil; import com.lkl.laop.sdk.Config2; import com.lkl.laop.sdk.LKLSDK; +import com.lkl.laop.sdk.auth.PrivateKeySigner; import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.utils.I18nUtil; -import com.wechat.pay.java.service.payments.nativepay.NativePayService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; -import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; -import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; @@ -118,8 +117,8 @@ public class LakalaUtil { try { CertificateFactory cf = CertificateFactory.getInstance("X509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); - String publicKeyBase64 = Base64.encodeBase64String(cert.getPublicKey().getEncoded()); - System.out.println(publicKeyBase64); +// String publicKeyBase64 = Base64.encodeBase64String(cert.getPublicKey().getEncoded()); +// System.out.println(publicKeyBase64); cert.checkValidity(); return cert; } catch (CertificateExpiredException e) { @@ -156,6 +155,46 @@ public class LakalaUtil { } } + + /** + * 签名校验 + * @param authorization + * @param reqBody + * @param lklNotifyCerPath + * @return + */ + public static boolean verify(String authorization, String reqBody, String lklNotifyCerPath) { + try { + log.debug("拉卡拉 Authorization 内容:{}", authorization); + Map headerMap = getLakalaAuthorizationMap(authorization); + String timestamp = headerMap.get("timestamp"); + String nonceStr = headerMap.get("nonce_str"); + String signature = headerMap.get("signature"); + + X509Certificate lklNotifyCer = loadCertificate(new ClassPathResource(lklNotifyCerPath).getInputStream()); + if (StrUtil.isBlank(timestamp) || StrUtil.isBlank(nonceStr) || StrUtil.isBlank(signature) || lklNotifyCer == null) { + return false; + } + + StringBuilder preSignData = new StringBuilder(); + preSignData.append(timestamp).append("\n") + .append(nonceStr).append("\n") + .append(reqBody).append("\n"); + String preSignDataStr = preSignData.toString(); + log.debug("拉卡拉签名明文内容:{}", preSignDataStr); + if (verify(lklNotifyCer, preSignDataStr.getBytes(StandardCharsets.UTF_8), signature)) { + log.debug("验签成功"); + return true; + } + + log.debug("验签失败"); + return false; + } catch (Exception e) { + log.error("验签发生异常:{}", e); + return false; + } + } + /** * 解析请求头中的认证签名等信息 * 参考:https://o.lakala.com/#/home/document/detail?id=36