拉卡拉分账调试修正

This commit is contained in:
Jack 2025-02-13 22:06:10 +08:00
parent 827b623cfb
commit cd280458f0
4 changed files with 81 additions and 19 deletions

View File

@ -19,6 +19,7 @@ import org.springframework.web.multipart.MultipartFile;
import org.springframework.util.Base64Utils; import org.springframework.util.Base64Utils;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
@Api(tags = "拉卡拉相关接口 - 前端控制器") @Api(tags = "拉卡拉相关接口 - 前端控制器")
@ -44,8 +45,8 @@ public class LakalaController extends BaseControllerImpl {
@ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调") @ApiOperation(value = "商户分账业务开通申请异步回调回调", notes = "商户分账业务开通申请异步回调回调")
@RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST) @RequestMapping(value = "/ledger/applyLedgerMerNotify", method = RequestMethod.POST)
public JSONObject ledgerApplyLedgerMerNotify(@RequestBody JSONObject paramsJSON) { public JSONObject ledgerApplyLedgerMerNotify(HttpServletRequest request) {
return lakalaPayService.applyLedgerMerNotify(paramsJSON); return lakalaPayService.applyLedgerMerNotify(request);
} }
@ApiOperation(value = "分账接收方创建申请", notes = "分账接收方创建申请") @ApiOperation(value = "分账接收方创建申请", notes = "分账接收方创建申请")
@ -62,7 +63,7 @@ public class LakalaController extends BaseControllerImpl {
@ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知") @ApiOperation(value = "分账关系绑定申请异步回调通知", notes = "分账关系绑定申请异步回调通知")
@RequestMapping(value = "/ledger/applyBindNotify", method = RequestMethod.POST) @RequestMapping(value = "/ledger/applyBindNotify", method = RequestMethod.POST)
public JSONObject applyBindNotify(@RequestBody JSONObject paramsJSON) { public JSONObject applyBindNotify(HttpServletRequest request) {
return lakalaPayService.applyLedgerMerReceiverBindNotify(paramsJSON); return lakalaPayService.applyLedgerMerReceiverBindNotify(request);
} }
} }

View File

@ -100,10 +100,10 @@ public interface LakalaPayService {
* 商户分账业务开通申请回调 * 商户分账业务开通申请回调
* 参考https://o.lakala.com/#/home/document/detail?id=379 * 参考https://o.lakala.com/#/home/document/detail?id=379
* *
* @param paramsJSON * @param request
* @return * @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 * 参考https://o.lakala.com/#/home/document/detail?id=379
* *
* @param paramsJSON * @param request
* @return * @return
*/ */
JSONObject applyLedgerMerReceiverBindNotify(JSONObject paramsJSON); JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request);
} }

View File

@ -65,6 +65,8 @@ public class LakalaPayServiceImpl implements LakalaPayService {
private String priKeyPath; //商户私钥信息地址 private String priKeyPath; //商户私钥信息地址
@Value("${lakala.lkl_platform_cer_path}") @Value("${lakala.lkl_platform_cer_path}")
private String lklCerPath; //拉卡拉支付平台证书地址 private String lklCerPath; //拉卡拉支付平台证书地址
@Value("${lakala.api_cert_path}")
private String apiCertPath;
@Value("${lakala.lkl_platform_cer_path}") @Value("${lakala.lkl_platform_cer_path}")
private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签) private String lklNotifyCerPath; //拉卡拉支付平台证书地址2(用于拉卡拉通知验签)
@Value("${lakala.org_code}") @Value("${lakala.org_code}")
@ -465,12 +467,21 @@ public class LakalaPayServiceImpl implements LakalaPayService {
* 商户分账业务开通申请回调 * 商户分账业务开通申请回调
* 参考https://o.lakala.com/#/home/document/detail?id=379 * 参考https://o.lakala.com/#/home/document/detail?id=379
* *
* @param paramsJSON * @param request
* @return * @return
*/ */
@Override @Override
public JSONObject applyLedgerMerNotify(JSONObject paramsJSON) { public JSONObject applyLedgerMerNotify(HttpServletRequest request) {
// TODO 验签 // 验签
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(); JSONObject respData = new JSONObject();
respData.put("retCode", "OP90003"); respData.put("retCode", "OP90003");
@ -668,12 +679,23 @@ public class LakalaPayServiceImpl implements LakalaPayService {
* 分账关系绑定申请回调 * 分账关系绑定申请回调
* 参考https://o.lakala.com/#/home/document/detail?id=379 * 参考https://o.lakala.com/#/home/document/detail?id=379
* *
* @param paramsJSON * @param request
* @return * @return
*/ */
@Override @Override
public JSONObject applyLedgerMerReceiverBindNotify(JSONObject paramsJSON) { public JSONObject applyLedgerMerReceiverBindNotify(HttpServletRequest request) {
// TODO 验签 // 验签
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(); JSONObject respData = new JSONObject();
respData.put("retCode", "OP90003"); respData.put("retCode", "OP90003");
respData.put("retMsg", "响应处理失败!"); respData.put("retMsg", "响应处理失败!");

View File

@ -8,16 +8,15 @@
package com.suisung.mall.pay.utils; package com.suisung.mall.pay.utils;
import cn.hutool.core.util.StrUtil;
import com.lkl.laop.sdk.Config2; import com.lkl.laop.sdk.Config2;
import com.lkl.laop.sdk.LKLSDK; 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.exception.ApiException;
import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.common.utils.I18nUtil;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -118,8 +117,8 @@ public class LakalaUtil {
try { try {
CertificateFactory cf = CertificateFactory.getInstance("X509"); CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream); X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
String publicKeyBase64 = Base64.encodeBase64String(cert.getPublicKey().getEncoded()); // String publicKeyBase64 = Base64.encodeBase64String(cert.getPublicKey().getEncoded());
System.out.println(publicKeyBase64); // System.out.println(publicKeyBase64);
cert.checkValidity(); cert.checkValidity();
return cert; return cert;
} catch (CertificateExpiredException e) { } 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<String, String> 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 * 参考https://o.lakala.com/#/home/document/detail?id=36