ref 校验注解改名, 请求参数增加随机数, 增加请求有效时长参数和校验

This commit is contained in:
DaxPay
2024-06-11 20:37:34 +08:00
parent 783164d8e7
commit 27e21470c1
30 changed files with 199 additions and 212 deletions

View File

@@ -8,15 +8,19 @@
- [ ] DEMO增加获取微信OpenID和支付宝OpenId功能
- [ ] 支付宝微信等消息通知地址支持一键生成
- [ ] 管理端界面支持扫码绑定对账接收方功能
- [ ] 请求IP参数增加正则校验
- [ ] 支付接口公共参数添加随机数字段, 预防重放问题
- [ ] 请求接口增加有效期校验, 一个请求十分钟后失效
- [x] 请求IP参数增加正则校验
- [x] 支付接口公共参数添加随机数字段, 预防重放问题
- [x] 请求接口增加有效期校验, 超时后失效
- [ ] 数据库表进行规则, 字段设置长度, 增加索引
- [ ] 订单
- [ ] 记录
- [ ] 配置
- [x] 订单和扩展信息进行合并
- [x] 支付通道两个独立的配置进行合并为一个
- [X] 去除有效, icon, 颜色等字段
- [x] 通道配置设置默认ICON
- [ ] 平台配置改版
- [ ] 增加接口请求有效时配置
- [x] 平台配置改版
- [x] 增加接口请求有效时配置
- [x] 平台配置和接口配置删除回调地址配置
- [X] 删除回调地址配置, 更换为消息通知地址和消息通知类型
- [X] 接口配置改版
@@ -47,7 +51,6 @@
- [ ] 微信新增V3版本接口
- [ ] 支付宝新增V3版本接口
- [ ] 增加各类日志记录,例如钱包的各项操作
- [ ] 数据库表进行规则, 字段设置长度, 增加索引
- [ ] 针对同步/对账等出现脏数据导致阻塞的问题, 进行优化
- [ ] 同步接口
- [ ] 对账接口

View File

@@ -19,7 +19,7 @@ public class LocalDateTimeUtil extends cn.hutool.core.date.LocalDateTimeUtil {
/**
* 是否在指定的时间范围内
*/
public boolean between(LocalDateTime now, LocalDateTime start, LocalDateTime end) {
public boolean inBetween(LocalDateTime now, LocalDateTime start, LocalDateTime end) {
return ge(now, start) && le(now, end);
}

View File

@@ -23,6 +23,9 @@ public abstract class DaxPayRequest<T extends DaxPayResponseModel> {
/** 请求时间,传输时间戳 */
private Long reqTime = DateUtil.currentSeconds();
/** 随机数 */
private String nonceStr;
/**
* 方法请求路径
* @return 请求路径

View File

@@ -23,6 +23,10 @@ public abstract class PaymentCommonParam {
@IpAddress
private String clientIp;
/** 随机数 */
@Schema(description = "随机数")
private String nonceStr;
/** 签名 */
@Schema(description = "签名")
private String sign;

View File

@@ -10,7 +10,7 @@ import cn.daxpay.single.result.DaxResult;
import cn.daxpay.single.result.allocation.AllocReceiverAddResult;
import cn.daxpay.single.result.allocation.AllocReceiverRemoveResult;
import cn.daxpay.single.result.allocation.AllocationResult;
import cn.daxpay.single.service.annotation.PaymentSign;
import cn.daxpay.single.service.annotation.PaymentVerify;
import cn.daxpay.single.service.annotation.InitPaymentContext;
import cn.daxpay.single.service.core.payment.allocation.service.AllocationReceiverService;
import cn.daxpay.single.service.core.payment.allocation.service.AllocationService;
@@ -39,7 +39,7 @@ public class UniAllocationController {
private final AllocationReceiverService receiverService;
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.ALLOCATION)
@Operation(summary = "发起分账接口")
@PostMapping("/start")
@@ -47,7 +47,7 @@ public class UniAllocationController {
return DaxRes.ok(allocationService.allocation(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.ALLOCATION_FINISH)
@Operation(summary = "分账完结接口")
@PostMapping("/finish")
@@ -55,7 +55,7 @@ public class UniAllocationController {
return DaxRes.ok(allocationService.finish(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.ALLOCATION_RECEIVER_ADD)
@Operation(summary = "分账接收方添加接口")
@PostMapping("/receiver/add")
@@ -63,7 +63,7 @@ public class UniAllocationController {
return DaxRes.ok(receiverService.addAndSync(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.ALLOCATION_RECEIVER_REMOVE)
@Operation(summary = "分账接收方删除接口")
@PostMapping("/receiver/remove")

View File

@@ -10,7 +10,7 @@ import cn.daxpay.single.result.DaxResult;
import cn.daxpay.single.result.assist.WxAccessTokenResult;
import cn.daxpay.single.result.assist.WxAuthUrlResult;
import cn.daxpay.single.service.annotation.InitPaymentContext;
import cn.daxpay.single.service.annotation.PaymentSign;
import cn.daxpay.single.service.annotation.PaymentVerify;
import cn.daxpay.single.service.core.payment.assist.service.UniPayAssistService;
import cn.daxpay.single.util.DaxRes;
import io.swagger.v3.oas.annotations.Operation;
@@ -34,7 +34,7 @@ import org.springframework.web.bind.annotation.RestController;
public class UniPayAssistController {
private final UniPayAssistService uniPayAssistService;
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.GET_WX_AUTH_URL)
@Operation(summary = "获取微信OAuth2授权链接")
@PostMapping("/getWxAuthUrl")
@@ -42,7 +42,7 @@ public class UniPayAssistController {
return DaxRes.ok(uniPayAssistService.getWxAuthUrl(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.GET_WX_ACCESS_TOKEN)
@Operation(summary = "获取微信AccessToken")
@PostMapping("/getWxAccessToken")

View File

@@ -13,7 +13,7 @@ import cn.daxpay.single.result.pay.PayCloseResult;
import cn.daxpay.single.result.pay.PayResult;
import cn.daxpay.single.result.pay.RefundResult;
import cn.daxpay.single.result.transfer.TransferResult;
import cn.daxpay.single.service.annotation.PaymentSign;
import cn.daxpay.single.service.annotation.PaymentVerify;
import cn.daxpay.single.service.annotation.InitPaymentContext;
import cn.daxpay.single.service.core.payment.cancel.service.PayCancelService;
import cn.daxpay.single.service.core.payment.close.service.PayCloseService;
@@ -46,7 +46,7 @@ public class UniPayController {
private final PayCancelService payCancelService;
private final TransferService transferService;
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.PAY)
@Operation(summary = "统一支付接口")
@PostMapping("/pay")
@@ -54,7 +54,7 @@ public class UniPayController {
return DaxRes.ok(payService.pay(payParam));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.CLOSE)
@Operation(summary = "支付关闭接口")
@PostMapping("/close")
@@ -62,7 +62,7 @@ public class UniPayController {
return DaxRes.ok(payCloseService.close(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.CANCEL)
@Operation(summary = "支付撤销接口")
@PostMapping("/cancel")
@@ -70,7 +70,7 @@ public class UniPayController {
return DaxRes.ok(payCancelService.cancel(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.REFUND)
@Operation(summary = "统一退款接口")
@PostMapping("/refund")
@@ -78,7 +78,7 @@ public class UniPayController {
return DaxRes.ok(refundService.refund(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.TRANSFER)
@Operation(summary = "统一转账接口")
@PostMapping("/transfer")

View File

@@ -9,7 +9,7 @@ import cn.daxpay.single.result.DaxResult;
import cn.daxpay.single.result.sync.AllocSyncResult;
import cn.daxpay.single.result.sync.PaySyncResult;
import cn.daxpay.single.result.sync.RefundSyncResult;
import cn.daxpay.single.service.annotation.PaymentSign;
import cn.daxpay.single.service.annotation.PaymentVerify;
import cn.daxpay.single.service.annotation.InitPaymentContext;
import cn.daxpay.single.service.core.payment.allocation.service.AllocationSyncService;
import cn.daxpay.single.service.core.payment.sync.service.PaySyncService;
@@ -39,7 +39,7 @@ public class UniPaySyncController {
private final RefundSyncService refundSyncService;
private final AllocationSyncService allocationSyncService;
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.SYNC_PAY)
@Operation(summary = "支付同步接口")
@PostMapping("/pay")
@@ -47,7 +47,7 @@ public class UniPaySyncController {
return DaxRes.ok(paySyncService.sync(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.SYNC_REFUND)
@Operation(summary = "退款同步接口")
@PostMapping("/refund")
@@ -56,7 +56,7 @@ public class UniPaySyncController {
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.SYNC_ALLOCATION)
@Operation(summary = "分账同步接口")
@PostMapping("/allocation")
@@ -64,7 +64,7 @@ public class UniPaySyncController {
return DaxRes.ok(allocationSyncService.sync(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.SYNC_TRANSFER)
@Operation(summary = "转账同步接口")
@PostMapping("/transfer")

View File

@@ -13,7 +13,7 @@ import cn.daxpay.single.result.order.AllocOrderResult;
import cn.daxpay.single.result.allocation.AllocReceiversResult;
import cn.daxpay.single.result.order.PayOrderResult;
import cn.daxpay.single.result.order.RefundOrderResult;
import cn.daxpay.single.service.annotation.PaymentSign;
import cn.daxpay.single.service.annotation.PaymentVerify;
import cn.daxpay.single.service.annotation.InitPaymentContext;
import cn.daxpay.single.service.core.order.pay.service.PayOrderQueryService;
import cn.daxpay.single.service.core.order.refund.service.RefundOrderQueryService;
@@ -46,7 +46,7 @@ public class UniQueryController {
private final AllocationReceiverService allocationReceiverService;
private final AllocationService allocationService;
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.QUERY_PAY_ORDER)
@Operation(summary = "支付订单查询接口")
@PostMapping("/payOrder")
@@ -54,7 +54,7 @@ public class UniQueryController {
return DaxRes.ok(payOrderQueryService.queryPayOrder(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.QUERY_REFUND_ORDER)
@Operation(summary = "退款订单查询接口")
@PostMapping("/refundOrder")
@@ -62,7 +62,7 @@ public class UniQueryController {
return DaxRes.ok(refundOrderQueryService.queryRefundOrder(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.QUERY_ALLOCATION_ORDER)
@Operation(summary = "分账订单查询接口")
@PostMapping("/allocationOrder")
@@ -70,7 +70,7 @@ public class UniQueryController {
return DaxRes.ok(allocationService.queryAllocationOrder(param));
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.QUERY_TRANSFER_ORDER)
@Operation(summary = "转账订单查询接口")
@PostMapping("/transferOrder")
@@ -78,7 +78,7 @@ public class UniQueryController {
return DaxRes.ok();
}
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.QUERY_ALLOCATION_RECEIVER)
@Operation(summary = "分账接收方查询接口")
@PostMapping("/allocationReceiver")

View File

@@ -3,7 +3,7 @@ package cn.daxpay.single.gateway.controller;
import cn.bootx.platform.common.core.annotation.IgnoreAuth;
import cn.daxpay.single.code.PaymentApiCode;
import cn.daxpay.single.result.DaxResult;
import cn.daxpay.single.service.annotation.PaymentSign;
import cn.daxpay.single.service.annotation.PaymentVerify;
import cn.daxpay.single.service.annotation.InitPaymentContext;
import cn.daxpay.single.util.DaxRes;
import io.swagger.v3.oas.annotations.Operation;
@@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class UniReconcileController {
@PaymentSign
@PaymentVerify
@InitPaymentContext(PaymentApiCode.PAY)
@Operation(summary = "下载指定日期的资金流水")
@PostMapping("/pay")

View File

@@ -3,7 +3,7 @@ package cn.daxpay.single.service.annotation;
import java.lang.annotation.*;
/**
* 支付校验签名标识
* 支付校验校验标识
* 支付方法至少有一个参数并且需要签名支付参数需要放在第一位
* 返回对象必须为 ResResult<T extends PaymentCommonResult> 格式
* @author xxm
@@ -13,5 +13,5 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface PaymentSign {
public @interface PaymentVerify {
}

View File

@@ -1,21 +0,0 @@
package cn.daxpay.single.service.common.context;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 支付接口信息
* @author xxm
* @since 2023/12/24
*/
@Data
@Accessors(chain = true)
public class ApiInfoLocal {
/** 当前支付接口编码 */
private String apiCode;
/** 回调地址 */
private String noticeUrl;
}

View File

@@ -10,7 +10,7 @@ import lombok.experimental.Accessors;
*/
@Data
@Accessors(chain = true)
public class RequestLocal {
public class ClientLocal {
/** 客户端ip */
private String clientIp;

View File

@@ -1,15 +0,0 @@
package cn.daxpay.single.service.common.context;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 支付同步信息
* @author xxm
* @since 2024/1/24
*/
@Data
@Accessors(chain = true)
public class PaySyncLocal {
}

View File

@@ -15,6 +15,9 @@ public class PaymentContext {
/** 平台全局配置 */
private final PlatformLocal platformInfo = new PlatformLocal();
/** 请求终端信息 */
private final ClientLocal clientInfo = new ClientLocal();
/** 支付相关信息 */
private final PayLocal payInfo = new PayLocal();
@@ -24,12 +27,6 @@ public class PaymentContext {
/** 回调相关信息 */
private final CallbackLocal callbackInfo = new CallbackLocal();
/** 请求相关信息 */
private final RequestLocal requestInfo = new RequestLocal();
/** 支付同步相关信息 */
private final PaySyncLocal paySyncInfo = new PaySyncLocal();
/** 修复相关信息 */
private final RepairLocal repairInfo = new RepairLocal();

View File

@@ -28,6 +28,13 @@ public class PlatformLocal {
/** 是否对请求进行验签 */
private boolean reqSign;
/**
* 请求有效时长(秒)
* 如果传输的请求时间早于当前服务时间, 而且差值超过配置的时长, 将会请求失败
* 如果传输的请求时间比服务时间大于配置的时长(超过一分钟), 将会请求失败
*/
private Integer reqTimeout;
/** 消息通知方式 */
private String noticeType;

View File

@@ -1,14 +0,0 @@
package cn.daxpay.single.service.common.context;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 退款请求上下文
* @author xxm
* @since 2023/12/26
*/
@Data
@Accessors(chain = true)
public class RefundRequestLocal {
}

View File

@@ -167,7 +167,7 @@ public class AllocationSyncService {
.setSyncInfo(syncResult.getSyncInfo())
.setErrorCode(errorCode)
.setErrorMsg(errorMsg)
.setClientIp(PaymentContextLocal.get().getRequestInfo().getClientIp());
.setClientIp(PaymentContextLocal.get().getClientInfo().getClientIp());
paySyncRecordService.saveRecord(paySyncRecord);
}
}

View File

@@ -98,7 +98,7 @@ public class PayCancelService {
*/
private void saveRecord(PayOrder payOrder, boolean closed, String errMsg){
String clientIp = PaymentContextLocal.get()
.getRequestInfo()
.getClientInfo()
.getClientIp();
PayCloseRecord record = new PayCloseRecord()
.setOrderNo(payOrder.getOrderNo())

View File

@@ -105,7 +105,7 @@ public class PayCloseService {
*/
private void saveRecord(PayOrder payOrder, boolean closed, String errMsg){
String clientIp = PaymentContextLocal.get()
.getRequestInfo()
.getClientInfo()
.getClientIp();
PayCloseRecord record = new PayCloseRecord()
.setOrderNo(payOrder.getOrderNo())

View File

@@ -5,8 +5,8 @@ import cn.bootx.platform.common.core.util.ValidationUtil;
import cn.daxpay.single.exception.pay.PayFailureException;
import cn.daxpay.single.param.PaymentCommonParam;
import cn.daxpay.single.result.PaymentCommonResult;
import cn.daxpay.single.service.annotation.PaymentSign;
import cn.daxpay.single.service.core.payment.common.service.PaymentSignService;
import cn.daxpay.single.service.annotation.PaymentVerify;
import cn.daxpay.single.service.core.payment.common.service.PaymentAssistService;
import cn.daxpay.single.util.DaxRes;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -27,11 +27,11 @@ import org.springframework.stereotype.Component;
@Component
@Order()
@RequiredArgsConstructor
public class PaymentVerifySignAop {
private final PaymentSignService paymentSignService;
public class PaymentVerifyAop {
private final PaymentAssistService paymentAssistService;
@Around("@annotation(paymentSign)")
public Object beforeMethod(ProceedingJoinPoint pjp, @SuppressWarnings("unused") PaymentSign paymentSign) throws Throwable {
@Around("@annotation(paymentVerify)")
public Object beforeMethod(ProceedingJoinPoint pjp, @SuppressWarnings("unused") PaymentVerify paymentVerify) throws Throwable {
Object[] args = pjp.getArgs();
if (args.length == 0){
throw new PayFailureException("支付方法至少有一个参数,并且需要签名支付参数需要放在第一位");
@@ -40,8 +40,14 @@ public class PaymentVerifySignAop {
if (param instanceof PaymentCommonParam){
// 参数校验
ValidationUtil.validateParam(param);
// 参数验签
paymentSignService.verifySign((PaymentCommonParam) param);
// 请求上下文初始化
paymentAssistService.initRequest((PaymentCommonParam) param);
// 参数签名校验
paymentAssistService.signVerify((PaymentCommonParam) param);
// 参数请求时间校验
paymentAssistService.reqTimeoutVerify((PaymentCommonParam) param);
} else {
throw new PayFailureException("支付参数需要继承PayCommonParam");
}
@@ -54,14 +60,14 @@ public class PaymentVerifySignAop {
// todo 后期错误码统一管理后进行更改
commonResult.setCode(1);
commonResult.setMsg(ex.getMessage());
paymentSignService.sign(commonResult);
paymentAssistService.sign(commonResult);
return DaxRes.ok(commonResult);
}
// 对返回值进行签名
if (proceed instanceof ResResult){
Object data = ((ResResult<?>) proceed).getData();
if (data instanceof PaymentCommonResult){
paymentSignService.sign((PaymentCommonResult) data);
paymentAssistService.sign((PaymentCommonResult) data);
} else {
throw new PayFailureException("支付方法返回类型需要为 ResResult<T extends PaymentCommonResult> 格式");
}

View File

@@ -1,13 +1,23 @@
package cn.daxpay.single.service.core.payment.common.service;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.daxpay.single.code.PaySignTypeEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
import cn.daxpay.single.param.PaymentCommonParam;
import cn.daxpay.single.service.common.context.RequestLocal;
import cn.daxpay.single.result.PaymentCommonResult;
import cn.daxpay.single.service.common.context.ClientLocal;
import cn.daxpay.single.service.common.context.PlatformLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.system.config.service.PlatformConfigService;
import cn.daxpay.single.util.PaySignUtil;
import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* 支付、退款等各类操作支持服务
* @author xxm
@@ -19,18 +29,90 @@ import org.springframework.stereotype.Service;
public class PaymentAssistService {
private final PlatformConfigService platformConfigService;
/**
* 初始化上下文
*/
public void initContext(PaymentCommonParam paymentCommonParam){
platformConfigService.initPlatform();
this.initRequest(paymentCommonParam);
}
/**
* 初始化请求相关信息上下文
*/
public void initRequest(PaymentCommonParam paymentCommonParam){
RequestLocal request = PaymentContextLocal.get().getRequestInfo();
ClientLocal request = PaymentContextLocal.get().getClientInfo();
request.setClientIp(paymentCommonParam.getClientIp());
}
/**
* 入参签名校验
*/
public void signVerify(PaymentCommonParam param) {
PlatformLocal platformInfo = PaymentContextLocal.get().getPlatformInfo();
// 如果平台配置所有属性为空, 进行初始化
if (BeanUtil.isEmpty(platformInfo)){
platformConfigService.initPlatform();
}
// 判断当前接口是否不需要签名
if (!platformInfo.isReqSign()){
return;
}
// 参数转换为Map对象
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
String signType = platform.getSignType();
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
boolean verified = PaySignUtil.verifyHmacSha256Sign(param, platform.getSignSecret(), param.getSign());
if (!verified){
throw new PayFailureException("未通过签名验证");
}
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
boolean verified = PaySignUtil.verifyMd5Sign(param, platform.getSignSecret(), param.getSign());
if (!verified){
throw new PayFailureException("未通过签名验证");
}
} else {
throw new PayFailureException("签名方式错误");
}
}
/**
* 请求有效时间校验
*/
public void reqTimeoutVerify(PaymentCommonParam param) {
PlatformLocal platformInfo = PaymentContextLocal.get().getPlatformInfo();
// 如果平台配置所有属性为空, 进行初始化
if (BeanUtil.isEmpty(platformInfo)){
platformConfigService.initPlatform();
}
if (Objects.nonNull(platformInfo.getReqTimeout()) ){
LocalDateTime now = LocalDateTime.now();
// 时间差值(秒)
long durationSeconds = Math.abs(LocalDateTimeUtil.between(now, param.getReqTime()).getSeconds());
// 当前时间是否晚于请求时间
if (LocalDateTimeUtil.lt(now, param.getReqTime())){
// 请求时间比服务器时间晚, 超过一分钟直接打回
if (durationSeconds > 60){
throw new PayFailureException("请求时间晚于服务器接收到的时间,请检查");
}
} else {
// 请求时间比服务器时间早, 超过配置时间直接打回
if (durationSeconds > platformInfo.getReqTimeout()){
throw new PayFailureException("请求已过期,请重新发送!");
}
}
}
}
/**
* 对对象进行签名
*/
public void sign(PaymentCommonResult result) {
PlatformLocal platformInfo = PaymentContextLocal.get().getPlatformInfo();
// 如果平台配置所有属性为空, 进行初始化
if (BeanUtil.isEmpty(platformInfo)){
platformConfigService.initPlatform();
}
String signType = platformInfo.getSignType();
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
result.setSign(PaySignUtil.hmacSha256Sign(result, platformInfo.getSignSecret()));
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
result.setSign(PaySignUtil.md5Sign(result, platformInfo.getSignSecret()));
} else {
throw new PayFailureException("未获取到签名方式,请检查");
}
}
}

View File

@@ -1,80 +0,0 @@
package cn.daxpay.single.service.core.payment.common.service;
import cn.daxpay.single.code.PaySignTypeEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
import cn.daxpay.single.param.PaymentCommonParam;
import cn.daxpay.single.result.PaymentCommonResult;
import cn.daxpay.single.service.common.context.PlatformLocal;
import cn.daxpay.single.service.common.local.PaymentContextLocal;
import cn.daxpay.single.service.core.system.config.service.PlatformConfigService;
import cn.daxpay.single.util.PaySignUtil;
import cn.hutool.core.bean.BeanUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Objects;
/**
* 支付签名服务
* @author xxm
* @since 2023/12/24
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class PaymentSignService {
private final PaymentAssistService paymentAssistService;
private final PlatformConfigService platformConfigService;
/**
* 入参签名校验
*/
public void verifySign(PaymentCommonParam param) {
// 先触发上下文的初始化
paymentAssistService.initContext(param);
PlatformLocal platformInfo = PaymentContextLocal.get().getPlatformInfo();
// 判断当前接口是否不需要签名
if (!platformInfo.isReqSign()){
return;
}
// 参数转换为Map对象
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
String signType = platform.getSignType();
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
boolean verified = PaySignUtil.verifyHmacSha256Sign(param, platform.getSignSecret(), param.getSign());
if (!verified){
throw new PayFailureException("未通过签名验证");
}
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
boolean verified = PaySignUtil.verifyMd5Sign(param, platform.getSignSecret(), param.getSign());
if (!verified){
throw new PayFailureException("未通过签名验证");
}
} else {
throw new PayFailureException("签名方式错误");
}
}
/**
* 对对象进行签名
*/
public void sign(PaymentCommonResult result) {
PlatformLocal platformInfo = PaymentContextLocal.get().getPlatformInfo();
// 如果平台配置所有属性为空, 进行初始化
if (BeanUtil.isEmpty(platformInfo)){
platformConfigService.initPlatform();
}
String signType = platformInfo.getSignType();
if (Objects.equals(PaySignTypeEnum.HMAC_SHA256.getCode(), signType)){
result.setSign(PaySignUtil.hmacSha256Sign(result, platformInfo.getSignSecret()));
} else if (Objects.equals(PaySignTypeEnum.MD5.getCode(), signType)){
result.setSign(PaySignUtil.md5Sign(result, platformInfo.getSignSecret()));
} else {
throw new PayFailureException("未获取到签名方式,请检查");
}
}
}

View File

@@ -10,7 +10,7 @@ import cn.daxpay.single.service.core.order.pay.convert.PayOrderConvert;
import cn.daxpay.single.service.core.order.pay.entity.PayOrder;
import cn.daxpay.single.service.core.order.refund.convert.RefundOrderConvert;
import cn.daxpay.single.service.core.order.refund.entity.RefundOrder;
import cn.daxpay.single.service.core.payment.common.service.PaymentSignService;
import cn.daxpay.single.service.core.payment.common.service.PaymentAssistService;
import cn.daxpay.single.service.core.payment.notice.result.AllocDetailNoticeResult;
import cn.daxpay.single.service.core.payment.notice.result.AllocNoticeResult;
import cn.daxpay.single.service.core.payment.notice.result.PayNoticeResult;
@@ -32,7 +32,7 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor
public class ClientNoticeAssistService {
private final PaymentSignService paymentSignService;
private final PaymentAssistService paymentAssistService;
/**
* 构建出支付通知任务对象
@@ -40,7 +40,7 @@ public class ClientNoticeAssistService {
public ClientNoticeTask buildPayTask(PayOrder order){
PayNoticeResult payNoticeResult = PayOrderConvert.CONVERT.convertNotice(order);
payNoticeResult.setAttach(order.getAttach());
paymentSignService.sign(payNoticeResult);
paymentAssistService.sign(payNoticeResult);
return new ClientNoticeTask()
.setUrl(order.getNotifyUrl())
// 时间序列化进行了重写, 所以使用Jackson的序列化工具类
@@ -60,7 +60,7 @@ public class ClientNoticeAssistService {
RefundNoticeResult refundNoticeResult = RefundOrderConvert.CONVERT.convertNotice(order);
refundNoticeResult.setAttach(order.getAttach());
// 签名
paymentSignService.sign(refundNoticeResult);
paymentAssistService.sign(refundNoticeResult);
return new ClientNoticeTask()
.setUrl(order.getNotifyUrl())
// 时间序列化进行了重写
@@ -86,7 +86,7 @@ public class ClientNoticeAssistService {
allocOrderResult.setAttach(order.getAttach())
.setDetails(details);
// 签名
paymentSignService.sign(allocOrderResult);
paymentAssistService.sign(allocOrderResult);
return new ClientNoticeTask()
.setUrl(order.getNotifyUrl())
// 时间序列化进行了重写

View File

@@ -243,7 +243,7 @@ public class PaySyncService {
.setRepair(repair)
.setRepairNo(repairOrderNo)
.setErrorMsg(errorMsg)
.setClientIp(PaymentContextLocal.get().getRequestInfo().getClientIp());
.setClientIp(PaymentContextLocal.get().getClientInfo().getClientIp());
paySyncRecordService.saveRecord(paySyncRecord);
}

View File

@@ -5,7 +5,6 @@ import cn.bootx.platform.common.core.exception.RepetitiveOperationException;
import cn.daxpay.single.code.RefundStatusEnum;
import cn.daxpay.single.code.RefundSyncStatusEnum;
import cn.daxpay.single.exception.pay.PayFailureException;
import cn.daxpay.single.exception.pay.PayUnsupportedMethodException;
import cn.daxpay.single.param.payment.refund.RefundSyncParam;
import cn.daxpay.single.result.sync.RefundSyncResult;
import cn.daxpay.single.service.code.PayRepairSourceEnum;
@@ -23,12 +22,10 @@ import cn.daxpay.single.service.core.record.sync.entity.PaySyncRecord;
import cn.daxpay.single.service.core.record.sync.service.PaySyncRecordService;
import cn.daxpay.single.service.func.AbsRefundSyncStrategy;
import cn.daxpay.single.service.util.PayStrategyFactory;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@@ -203,7 +200,7 @@ public class RefundSyncService {
.setRepair(repair)
.setRepairNo(repairOrderNo)
.setErrorMsg(errorMsg)
.setClientIp(PaymentContextLocal.get().getRequestInfo().getClientIp());
.setClientIp(PaymentContextLocal.get().getClientInfo().getClientIp());
paySyncRecordService.saveRecord(paySyncRecord);
}

View File

@@ -42,6 +42,14 @@ public class PlatformConfig extends MpBaseEntity implements EntityBaseFunction<P
@DbColumn(comment = "是否对请求进行验签")
private boolean reqSign;
/**
* 请求有效时长(秒)
* 如果传输的请求时间早于当前服务时间, 而且差值超过配置的时长, 将会请求失败
* 如果传输的请求时间比服务时间大于配置的时长(超过一分钟), 将会请求失败
*/
@DbColumn(comment = "请求有效时长(秒)")
private Integer reqTimeout;
/**
* 消息通知方式, 目前只支持http
* @see TradeNotifyTypeEnum

View File

@@ -47,12 +47,6 @@ public class PlatformConfigService {
public void initPlatform(){
PlatformConfig config = this.getConfig();
PlatformLocal platform = PaymentContextLocal.get().getPlatformInfo();
platform.setSignType(config.getSignType());
platform.setSignSecret(config.getSignSecret());
platform.setOrderTimeout(config.getOrderTimeout());
platform.setLimitAmount(config.getLimitAmount());
platform.setWebsiteUrl(config.getWebsiteUrl());
platform.setNoticeType(config.getNotifyType());
platform.setNoticeUrl(config.getNotifyUrl());
BeanUtil.copyProperties(config,platform);
}
}

View File

@@ -33,6 +33,14 @@ public class PlatformConfigDto {
@Schema(description = "是否对请求进行验签")
private boolean reqSign;
/**
* 请求有效时长(秒)
* 如果传输的请求时间早于当前服务时间, 而且差值超过配置的时长, 将会请求失败
* 如果传输的请求时间比服务时间大于配置的时长(超过一分钟), 将会请求失败
*/
@Schema(description = "请求有效时长(秒)")
private Integer reqTimeout;
/**
* 消息通知方式, 目前只支持http
* @see TradeNotifyTypeEnum

View File

@@ -23,6 +23,14 @@ public class PlatformConfigParam {
@Schema(description = "是否对请求进行验签")
private boolean reqSign;
/**
* 请求有效时长(秒)
* 如果传输的请求时间早于当前服务时间, 而且差值超过配置的时长, 将会请求失败
* 如果传输的请求时间比服务时间大于配置的时长(超过一分钟), 将会请求失败
*/
@Schema(description = "请求有效时长(秒)")
private Integer reqTimeout;
/**
* @see PaySignTypeEnum
*/