feat(payment): 微信支付支持公钥和证书两种验证方式- 在 WechatPaymentSetting 中添加 publicType 字段,用于选择验证方式
- 修改 WechatPlugin 中的支付、退款等方法,支持两种验证方式 - 新增 getPublicKeyConfig 和 getCertificateConfig 方法,分别用于获取公钥和证书配置 - 优化退款通知处理逻辑,使用 NotificationParser 进行验证和解析
This commit is contained in:
parent
633b94c375
commit
0cf464e549
@ -1,9 +1,7 @@
|
|||||||
package cn.lili.modules.payment.kit.plugin.wechat;
|
package cn.lili.modules.payment.kit.plugin.wechat;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.net.URLDecoder;
|
import cn.hutool.core.net.URLDecoder;
|
||||||
import cn.hutool.core.net.URLEncoder;
|
import cn.hutool.core.net.URLEncoder;
|
||||||
import cn.hutool.json.JSONObject;
|
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import cn.lili.cache.Cache;
|
import cn.lili.cache.Cache;
|
||||||
import cn.lili.common.enums.ResultCode;
|
import cn.lili.common.enums.ResultCode;
|
||||||
@ -24,8 +22,6 @@ import cn.lili.modules.payment.entity.RefundLog;
|
|||||||
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
|
||||||
import cn.lili.modules.payment.kit.CashierSupport;
|
import cn.lili.modules.payment.kit.CashierSupport;
|
||||||
import cn.lili.modules.payment.kit.Payment;
|
import cn.lili.modules.payment.kit.Payment;
|
||||||
import cn.lili.modules.payment.kit.core.PaymentHttpResponse;
|
|
||||||
import cn.lili.modules.payment.kit.core.enums.RequestMethodEnums;
|
|
||||||
import cn.lili.modules.payment.kit.core.enums.SignType;
|
import cn.lili.modules.payment.kit.core.enums.SignType;
|
||||||
import cn.lili.modules.payment.kit.core.kit.HttpKit;
|
import cn.lili.modules.payment.kit.core.kit.HttpKit;
|
||||||
import cn.lili.modules.payment.kit.core.kit.IpKit;
|
import cn.lili.modules.payment.kit.core.kit.IpKit;
|
||||||
@ -34,9 +30,8 @@ import cn.lili.modules.payment.kit.core.utils.DateTimeZoneUtil;
|
|||||||
import cn.lili.modules.payment.kit.dto.PayParam;
|
import cn.lili.modules.payment.kit.dto.PayParam;
|
||||||
import cn.lili.modules.payment.kit.dto.PaymentSuccessParams;
|
import cn.lili.modules.payment.kit.dto.PaymentSuccessParams;
|
||||||
import cn.lili.modules.payment.kit.params.dto.CashierParam;
|
import cn.lili.modules.payment.kit.params.dto.CashierParam;
|
||||||
import cn.lili.modules.payment.kit.plugin.wechat.enums.WechatApiEnum;
|
import cn.lili.modules.payment.kit.plugin.wechat.model.H5Info;
|
||||||
import cn.lili.modules.payment.kit.plugin.wechat.enums.WechatDomain;
|
import cn.lili.modules.payment.kit.plugin.wechat.model.SceneInfo;
|
||||||
import cn.lili.modules.payment.kit.plugin.wechat.model.*;
|
|
||||||
import cn.lili.modules.payment.service.PaymentService;
|
import cn.lili.modules.payment.service.PaymentService;
|
||||||
import cn.lili.modules.payment.service.RefundLogService;
|
import cn.lili.modules.payment.service.RefundLogService;
|
||||||
import cn.lili.modules.system.entity.dos.Setting;
|
import cn.lili.modules.system.entity.dos.Setting;
|
||||||
@ -58,7 +53,6 @@ import com.wechat.pay.java.core.exception.ValidationException;
|
|||||||
import com.wechat.pay.java.core.notification.NotificationConfig;
|
import com.wechat.pay.java.core.notification.NotificationConfig;
|
||||||
import com.wechat.pay.java.core.notification.NotificationParser;
|
import com.wechat.pay.java.core.notification.NotificationParser;
|
||||||
import com.wechat.pay.java.core.notification.RequestParam;
|
import com.wechat.pay.java.core.notification.RequestParam;
|
||||||
import com.wechat.pay.java.core.util.StringUtil;
|
|
||||||
import com.wechat.pay.java.service.payments.app.AppService;
|
import com.wechat.pay.java.service.payments.app.AppService;
|
||||||
import com.wechat.pay.java.service.payments.h5.H5Service;
|
import com.wechat.pay.java.service.payments.h5.H5Service;
|
||||||
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
|
||||||
@ -85,7 +79,6 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付
|
* 微信支付
|
||||||
@ -164,7 +157,13 @@ public class WechatPlugin implements Payment {
|
|||||||
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config config =this.getConfig(setting);
|
Config config =null;
|
||||||
|
if(setting.getPublicType().equals("CERT")){
|
||||||
|
config=this.getCertificateConfig(setting);
|
||||||
|
}else {
|
||||||
|
config=this.getPublicKeyConfig(setting);
|
||||||
|
}
|
||||||
|
|
||||||
// 构建service
|
// 构建service
|
||||||
H5Service service = new H5Service.Builder().config(config).build();
|
H5Service service = new H5Service.Builder().config(config).build();
|
||||||
|
|
||||||
@ -221,7 +220,12 @@ public class WechatPlugin implements Payment {
|
|||||||
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config config =this.getConfig(setting);
|
Config config =null;
|
||||||
|
if(setting.getPublicType().equals("CERT")){
|
||||||
|
config=this.getCertificateConfig(setting);
|
||||||
|
}else {
|
||||||
|
config=this.getPublicKeyConfig(setting);
|
||||||
|
}
|
||||||
// 构建service
|
// 构建service
|
||||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||||
|
|
||||||
@ -275,7 +279,12 @@ public class WechatPlugin implements Payment {
|
|||||||
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config config =this.getConfig(setting);
|
Config config =null;
|
||||||
|
if(setting.getPublicType().equals("CERT")){
|
||||||
|
config=this.getCertificateConfig(setting);
|
||||||
|
}else {
|
||||||
|
config=this.getPublicKeyConfig(setting);
|
||||||
|
}
|
||||||
// 构建service
|
// 构建service
|
||||||
AppService service = new AppService.Builder().config(config).build();
|
AppService service = new AppService.Builder().config(config).build();
|
||||||
|
|
||||||
@ -331,7 +340,12 @@ public class WechatPlugin implements Payment {
|
|||||||
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config config =this.getConfig(setting);
|
Config config =null;
|
||||||
|
if(setting.getPublicType().equals("CERT")){
|
||||||
|
config=this.getCertificateConfig(setting);
|
||||||
|
}else {
|
||||||
|
config=this.getPublicKeyConfig(setting);
|
||||||
|
}
|
||||||
// 构建service
|
// 构建service
|
||||||
NativePayService service = new NativePayService.Builder().config(config).build();
|
NativePayService service = new NativePayService.Builder().config(config).build();
|
||||||
|
|
||||||
@ -395,7 +409,12 @@ public class WechatPlugin implements Payment {
|
|||||||
|
|
||||||
WechatPaymentSetting setting = wechatPaymentSetting();
|
WechatPaymentSetting setting = wechatPaymentSetting();
|
||||||
|
|
||||||
Config config =this.getConfig(setting);
|
Config config =null;
|
||||||
|
if(setting.getPublicType().equals("CERT")){
|
||||||
|
config=this.getCertificateConfig(setting);
|
||||||
|
}else {
|
||||||
|
config=this.getPublicKeyConfig(setting);
|
||||||
|
}
|
||||||
// 构建service
|
// 构建service
|
||||||
JsapiService service = new JsapiService.Builder().config(config).build();
|
JsapiService service = new JsapiService.Builder().config(config).build();
|
||||||
|
|
||||||
@ -491,7 +510,12 @@ public class WechatPlugin implements Payment {
|
|||||||
//获取微信设置
|
//获取微信设置
|
||||||
WechatPaymentSetting setting = wechatPaymentSetting();
|
WechatPaymentSetting setting = wechatPaymentSetting();
|
||||||
|
|
||||||
Config config =this.getConfig(setting);
|
Config config =null;
|
||||||
|
if(setting.getPublicType().equals("CERT")){
|
||||||
|
config=this.getCertificateConfig(setting);
|
||||||
|
}else {
|
||||||
|
config=this.getPublicKeyConfig(setting);
|
||||||
|
}
|
||||||
// 构建service
|
// 构建service
|
||||||
TransferBatchService service = new TransferBatchService.Builder().config(config).build();
|
TransferBatchService service = new TransferBatchService.Builder().config(config).build();
|
||||||
|
|
||||||
@ -547,14 +571,24 @@ public class WechatPlugin implements Payment {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
WechatPaymentSetting setting = wechatPaymentSetting();
|
WechatPaymentSetting setting = wechatPaymentSetting();
|
||||||
|
NotificationConfig config=null;
|
||||||
NotificationConfig config = new RSAAutoCertificateConfig.Builder()
|
if(setting.getPublicType().equals("CERT")) {
|
||||||
.merchantId(setting.getMchId())
|
config = new RSAAutoCertificateConfig.Builder()
|
||||||
.privateKey(setting.getApiclientKey())
|
.merchantId(setting.getMchId())
|
||||||
.merchantSerialNumber(setting.getSerialNumber())
|
.privateKey(setting.getApiclientKey())
|
||||||
.apiV3Key(setting.getApiKey3())
|
.merchantSerialNumber(setting.getSerialNumber())
|
||||||
.build();
|
.apiV3Key(setting.getApiKey3())
|
||||||
|
.build();
|
||||||
|
}else{
|
||||||
|
config = new RSAPublicKeyConfig.Builder()
|
||||||
|
.merchantId(setting.getMchId())
|
||||||
|
.apiV3Key(setting.getApiKey3())
|
||||||
|
.privateKey(setting.getApiclientKey())
|
||||||
|
.merchantSerialNumber(setting.getSerialNumber())
|
||||||
|
.publicKeyId(setting.getPublicId())
|
||||||
|
.publicKey(setting.getPublicKey())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化 NotificationParser
|
// 初始化 NotificationParser
|
||||||
NotificationParser parser = new NotificationParser(config);
|
NotificationParser parser = new NotificationParser(config);
|
||||||
@ -596,7 +630,12 @@ public class WechatPlugin implements Payment {
|
|||||||
//获取微信设置
|
//获取微信设置
|
||||||
WechatPaymentSetting setting = wechatPaymentSetting();
|
WechatPaymentSetting setting = wechatPaymentSetting();
|
||||||
|
|
||||||
Config config =this.getConfig(setting);
|
Config config =null;
|
||||||
|
if(setting.getPublicType().equals("CERT")){
|
||||||
|
config=this.getCertificateConfig(setting);
|
||||||
|
}else {
|
||||||
|
config=this.getPublicKeyConfig(setting);
|
||||||
|
}
|
||||||
// 构建service
|
// 构建service
|
||||||
RefundService refundService = new RefundService.Builder().config(config).build();
|
RefundService refundService = new RefundService.Builder().config(config).build();
|
||||||
|
|
||||||
@ -619,49 +658,45 @@ public class WechatPlugin implements Payment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refundNotify(HttpServletRequest request) {
|
public void refundNotify(HttpServletRequest request) {
|
||||||
String timestamp = request.getHeader("Wechatpay-Timestamp");
|
// 构造 RequestParam
|
||||||
String nonce = request.getHeader("Wechatpay-Nonce");
|
RequestParam requestParam = new RequestParam.Builder()
|
||||||
String serialNo = request.getHeader("Wechatpay-Serial");
|
.serialNumber(request.getHeader("Wechatpay-Serial"))
|
||||||
String signature = request.getHeader("Wechatpay-Signature");
|
.nonce(request.getHeader("Wechatpay-Nonce"))
|
||||||
|
.signature(request.getHeader("Wechatpay-Signature"))
|
||||||
|
.timestamp(request.getHeader("Wechatpay-Timestamp"))
|
||||||
|
.body(HttpKit.readData(request))
|
||||||
|
.build();
|
||||||
|
|
||||||
log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
|
|
||||||
String result = HttpKit.readData(request);
|
|
||||||
log.info("微信退款通知密文 {}", result);
|
|
||||||
JSONObject ciphertext = JSONUtil.parseObj(result);
|
|
||||||
WechatPaymentSetting setting = wechatPaymentSetting();
|
WechatPaymentSetting setting = wechatPaymentSetting();
|
||||||
try { //校验服务器端响应¬
|
NotificationConfig config=null;
|
||||||
String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
|
if(setting.getPublicType().equals("CERT")) {
|
||||||
wechatPaymentSetting().getApiKey3(), Objects.requireNonNull(setting.getPublicKey()));
|
config = new RSAAutoCertificateConfig.Builder()
|
||||||
log.info("微信退款通知明文 {}", plainText);
|
.merchantId(setting.getMchId())
|
||||||
|
.privateKey(setting.getApiclientKey())
|
||||||
|
.merchantSerialNumber(setting.getSerialNumber())
|
||||||
|
.apiV3Key(setting.getApiKey3())
|
||||||
|
.build();
|
||||||
|
}else{
|
||||||
|
config = new RSAPublicKeyConfig.Builder()
|
||||||
|
.merchantId(setting.getMchId())
|
||||||
|
.apiV3Key(setting.getApiKey3())
|
||||||
|
.privateKey(setting.getApiclientKey())
|
||||||
|
.merchantSerialNumber(setting.getSerialNumber())
|
||||||
|
.publicKeyId(setting.getPublicId())
|
||||||
|
.publicKey(setting.getPublicKey())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
if (("REFUND.SUCCESS").equals(ciphertext.getStr("event_type"))) {
|
// 初始化 NotificationParser
|
||||||
log.info("退款成功 {}", plainText);
|
NotificationParser parser = new NotificationParser(config);
|
||||||
//校验服务器端响应
|
try {
|
||||||
JSONObject jsonObject = JSONUtil.parseObj(plainText);
|
Refund refund = parser.parse(requestParam, Refund.class);
|
||||||
String transactionId = jsonObject.getStr("transaction_id");
|
RefundLog refundLog = refundLogService.getOne(new LambdaQueryWrapper<RefundLog>().eq(RefundLog::getPaymentReceivableNo,
|
||||||
String refundId = jsonObject.getStr("refund_id");
|
refund.getTransactionId()));
|
||||||
|
if (refundLog != null) {
|
||||||
RefundLog refundLog = refundLogService.getOne(new LambdaQueryWrapper<RefundLog>().eq(RefundLog::getPaymentReceivableNo,
|
refundLog.setIsRefund(true);
|
||||||
transactionId));
|
refundLog.setReceivableNo(refund.getRefundId());
|
||||||
if (refundLog != null) {
|
refundLogService.saveOrUpdate(refundLog);
|
||||||
refundLog.setIsRefund(true);
|
|
||||||
refundLog.setReceivableNo(refundId);
|
|
||||||
refundLogService.saveOrUpdate(refundLog);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log.info("退款失败 {}", plainText);
|
|
||||||
JSONObject jsonObject = JSONUtil.parseObj(plainText);
|
|
||||||
String transactionId = jsonObject.getStr("transaction_id");
|
|
||||||
String refundId = jsonObject.getStr("refund_id");
|
|
||||||
|
|
||||||
RefundLog refundLog = refundLogService.getOne(new LambdaQueryWrapper<RefundLog>().eq(RefundLog::getPaymentReceivableNo,
|
|
||||||
transactionId));
|
|
||||||
if (refundLog != null) {
|
|
||||||
refundLog.setReceivableNo(refundId);
|
|
||||||
refundLog.setErrorMessage(ciphertext.getStr("summary"));
|
|
||||||
refundLogService.saveOrUpdate(refundLog);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("微信退款失败", e);
|
log.error("微信退款失败", e);
|
||||||
@ -685,11 +720,11 @@ public class WechatPlugin implements Payment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取微信支付配置
|
* 获取微信公钥配置
|
||||||
* @param setting
|
* @param setting
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private RSAPublicKeyConfig getConfig(WechatPaymentSetting setting){
|
private RSAPublicKeyConfig getPublicKeyConfig(WechatPaymentSetting setting){
|
||||||
return
|
return
|
||||||
new RSAPublicKeyConfig.Builder()
|
new RSAPublicKeyConfig.Builder()
|
||||||
.merchantId(setting.getMchId())
|
.merchantId(setting.getMchId())
|
||||||
@ -701,6 +736,19 @@ public class WechatPlugin implements Payment {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取微信证书配置
|
||||||
|
* @param setting
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private RSAAutoCertificateConfig getCertificateConfig(WechatPaymentSetting setting) {
|
||||||
|
return new RSAAutoCertificateConfig.Builder()
|
||||||
|
.merchantId(setting.getMchId())
|
||||||
|
.privateKey(setting.getApiclientKey())
|
||||||
|
.merchantSerialNumber(setting.getSerialNumber())
|
||||||
|
.apiV3Key(setting.getApiKey3())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改订单支付单号
|
* 修改订单支付单号
|
||||||
|
@ -53,6 +53,11 @@ public class WechatPaymentSetting {
|
|||||||
* 公钥
|
* 公钥
|
||||||
*/
|
*/
|
||||||
private String publicKey;
|
private String publicKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信验证方式:公钥/证书(KEY/CERT)
|
||||||
|
*/
|
||||||
|
private String publicType;
|
||||||
// /**
|
// /**
|
||||||
// * pem 证书
|
// * pem 证书
|
||||||
// */
|
// */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user