Browse Source

支付服务统一退款添加退款前签名校验,保证资金安全

feature-1.1
wuxicheng 3 years ago
parent
commit
88caf1747a
  1. 18
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java
  2. 140
      bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/utils/MD5Util.java
  3. 16
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/dto/RefundDto.java
  4. 3
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/UnifiedOrderVo.java
  5. 15
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/UnifiedPayController.java
  6. 20
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumVerificationKey.java
  7. 4
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/UnifiedPayService.java
  8. 6
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java
  9. 39
      bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PaymentRefundUtil.java

18
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/enums/ResponseEnum.java

@ -11,26 +11,24 @@ public enum ResponseEnum {
SERVER_ERROR(500, "系统繁忙,请稍候重试!"), SERVER_ERROR(500, "系统繁忙,请稍候重试!"),
NOT_AUTH(500, "未登录!"), NOT_AUTH(500, "未登录!"),
PARAM_ERROR(400, "参数异常!"), PARAM_ERROR(400, "参数异常!"),
NOT_EXIST(110001, "查询为空"),
PAY_CONFIG_ERROR(110002, "支付配置未启用或未配置!"),
//======================订单异常======================== //======================业务异常========================
NOT_EXIST(110001, "查询为空"),
PAY_CONFIG_ERROR(110002, "支付配置未启用或未配置!"),
/** /**
* 订单已过期当前端看到该状态码的时候提示订单信息已过期请重新确认后提交此时用户点击确定前端刷新页面 * 订单已过期当前端看到该状态码的时候提示订单信息已过期请重新确认后提交此时用户点击确定前端刷新页面
*/ */
ORDER_EXPIRED(210001, "订单已过期"), ORDER_EXPIRED(110003, "订单已过期"),
/** /**
* 请勿重复提交订单 * 请勿重复提交订单
* 1.当前端遇到该异常时说明前端防多次点击没做好 * 1.当前端遇到该异常时说明前端防多次点击没做好
* 2.提示用户 订单已发生改变请勿重复下单 * 2.提示用户 订单已发生改变请勿重复下单
*/ */
REPEAT_ORDER(210002,"请勿重复提交订单"), REPEAT_ORDER(110004,"请勿重复提交订单"),
ORDER_CANCEL(110005, "该订单已取消,请重新下单!"),
ORDER_CANCEL(210003, "该订单已取消,请重新下单!"), ORDER_REPEAT_PAY(110006, "该订单已支付,请勿重复支付!"),
ORDER_REPEAT_PAY(210004, "该订单已支付,请勿重复支付!"), REFUND_SING_ERROR(110007, "签名错误!"),

140
bnyer-common/bnyer-common-core/src/main/java/com/bnyer/common/core/utils/MD5Util.java

@ -0,0 +1,140 @@
package com.bnyer.common.core.utils;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @author :WXC
* @Date :2023/05/12
* @description :
*/
public class MD5Util {
/**
* 默认的密码字符串组合用来将字节转换成 16 进制表示的字符,apache校验下载的文件的正确性用的就是默认的这个组合
*/
protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
protected static MessageDigest messagedigest = null;
static {
try {
messagedigest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsaex) {
System.err.println(MD5Util.class.getName()
+ "初始化失败,MessageDigest不支持MD5Util。");
nsaex.printStackTrace();
}
}
/**
* 生成字符串的md5校验值
*
* @param s
* @return
*/
public static String getMD5String(String s) {
return getMD5String(s.getBytes());
}
public static String getStaffMD5String(String staffId,String s) {
return getMD5String((staffId+s).getBytes());
}
public static String getUserMD5String(String userId,String s) {
return getMD5String(s.getBytes());
}
/**
* 判断字符串的md5校验码是否与一个已知的md5码相匹配
*
* @param password 要校验的字符串
* @param md5PwdStr 已知的md5校验码
* @return
*/
public static boolean checkPassword(String password, String md5PwdStr) {
String s = getMD5String(password);
return s.equals(md5PwdStr);
}
/**
* 生成文件的md5校验值
*
* @param file
* @return
* @throws IOException
*/
public static String getFileMD5String(File file) throws IOException {
InputStream fis;
fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int numRead = 0;
while ((numRead = fis.read(buffer)) > 0) {
messagedigest.update(buffer, 0, numRead);
}
fis.close();
return bufferToHex(messagedigest.digest());
}
public static String getFileMD5String(InputStream fis) throws IOException {
byte[] buffer = new byte[1024];
int numRead = 0;
while ((numRead = fis.read(buffer)) > 0) {
messagedigest.update(buffer, 0, numRead);
}
fis.close();
return bufferToHex(messagedigest.digest());
}
public static String getMD5String(byte[] bytes) {
messagedigest.update(bytes);
return bufferToHex(messagedigest.digest());
}
private static String bufferToHex(byte bytes[]) {
return bufferToHex(bytes, 0, bytes.length);
}
private static String bufferToHex(byte bytes[], int m, int n) {
StringBuffer stringbuffer = new StringBuffer(2 * n);
int k = m + n;
for (int l = m; l < k; l++) {
appendHexPair(bytes[l], stringbuffer);
}
return stringbuffer.toString();
}
private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
char c0 = hexDigits[(bt & 0xf0) >> 4];// 取字节中高 4 位的数字转换, >>> 为逻辑右移,将符号位一起右移,此处未发现两种符号有何不同
char c1 = hexDigits[bt & 0xf];// 取字节中低 4 位的数字转换
stringbuffer.append(c0);
stringbuffer.append(c1);
}
/**
* MD5方法
*
* @param text 明文
* @param key 密钥
* @return 密文
* @throws Exception
*/
public static String md5(String text, String key) throws Exception {
//加密后的字符串
System.out.println("text + key "+text + key);
String encodeStr= DigestUtils.md5Hex(text + key);
System.out.println("MD5加密后的字符串为:encodeStr="+encodeStr);
return encodeStr;
}
public static void main(String[] args) throws IOException {
System.out.println(MD5Util.getMD5String("RVWU202305121022211042vip"));
}
}

16
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/dto/RefundDto.java

@ -1,9 +1,13 @@
package com.bnyer.pay.bean.dto; package com.bnyer.pay.bean.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
/** /**
* @author :WXC * @author :WXC
* @Date :2023/05/08 * @Date :2023/05/08
@ -14,4 +18,16 @@ import lombok.Setter;
@NoArgsConstructor @NoArgsConstructor
public class RefundDto { public class RefundDto {
@NotBlank(message = "支付订单号不能为空")
@ApiModelProperty(value = "支付订单号")
private String payId;
@ApiModelProperty(value = " 退款金额(元) ,如果不传则全额退款", example = "0.01")
private BigDecimal refundAmount;
@NotBlank(message = "签名不能为空")
@ApiModelProperty(value = "签名")
private String sign;
} }

3
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/bean/vo/UnifiedOrderVo.java

@ -13,9 +13,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor @NoArgsConstructor
public class UnifiedOrderVo { public class UnifiedOrderVo {
@ApiModelProperty(value = "应用id")
private String appId;
@ApiModelProperty(value = "内部系统支付单号/开发者测单号") @ApiModelProperty(value = "内部系统支付单号/开发者测单号")
private String outOrderNo; private String outOrderNo;

15
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/controller/UnifiedPayController.java

@ -1,11 +1,16 @@
package com.bnyer.pay.controller; package com.bnyer.pay.controller;
import com.bnyer.common.core.domain.R; import com.bnyer.common.core.domain.R;
import com.bnyer.common.core.enums.ResponseEnum;
import com.bnyer.common.core.exception.ServiceException;
import com.bnyer.pay.bean.dto.RefundDto;
import com.bnyer.pay.bean.dto.UnifiedOrderDto; import com.bnyer.pay.bean.dto.UnifiedOrderDto;
import com.bnyer.pay.bean.dto.QueryOrderDto; import com.bnyer.pay.bean.dto.QueryOrderDto;
import com.bnyer.pay.bean.vo.ThirdRefundVo;
import com.bnyer.pay.service.UnifiedPayService; import com.bnyer.pay.service.UnifiedPayService;
import com.bnyer.pay.bean.vo.UnifiedOrderVo; import com.bnyer.pay.bean.vo.UnifiedOrderVo;
import com.bnyer.pay.bean.vo.QueryOrderVo; import com.bnyer.pay.bean.vo.QueryOrderVo;
import com.bnyer.pay.utils.PaymentRefundUtil;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -46,4 +51,14 @@ public class UnifiedPayController {
return R.ok(queryOrderVo); return R.ok(queryOrderVo);
} }
@PostMapping("/refund")
@Operation(summary = "统一退款" , description = "统一退款")
public R refund(@Valid @RequestBody RefundDto dto){
if (!PaymentRefundUtil.checkSign(dto)){
throw new ServiceException(ResponseEnum.REFUND_SING_ERROR);
}
ThirdRefundVo unifiedOrderVo = unifiedPayService.refund(dto);
return R.ok(unifiedOrderVo);
}
} }

20
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/enums/EnumVerificationKey.java

@ -0,0 +1,20 @@
package com.bnyer.pay.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
/**
* @author :WXC
* @Date :2023/05/12
* @description :
*/
@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum EnumVerificationKey {
VIP("vip", "VipInOrder20230512Key"),
;
private String key;
private String value;
}

4
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/UnifiedPayService.java

@ -1,7 +1,9 @@
package com.bnyer.pay.service; package com.bnyer.pay.service;
import com.bnyer.pay.bean.dto.RefundDto;
import com.bnyer.pay.bean.dto.UnifiedOrderDto; import com.bnyer.pay.bean.dto.UnifiedOrderDto;
import com.bnyer.pay.bean.dto.QueryOrderDto; import com.bnyer.pay.bean.dto.QueryOrderDto;
import com.bnyer.pay.bean.vo.ThirdRefundVo;
import com.bnyer.pay.bean.vo.UnifiedOrderVo; import com.bnyer.pay.bean.vo.UnifiedOrderVo;
import com.bnyer.pay.bean.vo.QueryOrderVo; import com.bnyer.pay.bean.vo.QueryOrderVo;
@ -28,4 +30,6 @@ public interface UnifiedPayService {
* @return * @return
*/ */
QueryOrderVo queryOrder(QueryOrderDto dto); QueryOrderVo queryOrder(QueryOrderDto dto);
ThirdRefundVo refund(RefundDto dto);
} }

6
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/service/impl/UnifiedPayServiceImpl.java

@ -18,6 +18,7 @@ import com.bnyer.pay.bean.bo.QueryOrderBo;
import com.bnyer.pay.bean.bo.UnifiedOrderBo; import com.bnyer.pay.bean.bo.UnifiedOrderBo;
import com.bnyer.pay.bean.dto.AddPayInfoDto; import com.bnyer.pay.bean.dto.AddPayInfoDto;
import com.bnyer.pay.bean.dto.QueryOrderDto; import com.bnyer.pay.bean.dto.QueryOrderDto;
import com.bnyer.pay.bean.dto.RefundDto;
import com.bnyer.pay.bean.dto.UnifiedOrderDto; import com.bnyer.pay.bean.dto.UnifiedOrderDto;
import com.bnyer.pay.bean.vo.*; import com.bnyer.pay.bean.vo.*;
import com.bnyer.pay.constant.KSPayConstants; import com.bnyer.pay.constant.KSPayConstants;
@ -222,6 +223,11 @@ public class UnifiedPayServiceImpl implements UnifiedPayService {
return queryOrderVo; return queryOrderVo;
} }
@Override
public ThirdRefundVo refund(RefundDto dto) {
return null;
}
/** /**
* 通过第三方系统支付状态构建业务系统对应支付状态 * 通过第三方系统支付状态构建业务系统对应支付状态
* @param payType * @param payType

39
bnyer-services/bnyer-pay/src/main/java/com/bnyer/pay/utils/PaymentRefundUtil.java

@ -0,0 +1,39 @@
package com.bnyer.pay.utils;
import com.bnyer.common.core.utils.MD5Util;
import com.bnyer.pay.bean.dto.RefundDto;
import com.bnyer.pay.enums.EnumVerificationKey;
/**
* @author :WXC
* @Date :2023/05/12
* @description : 退款工具类
*/
public class PaymentRefundUtil {
/**
* 获取签名
* @param dto
* @return
*/
public static String getSign(RefundDto dto) {
return MD5Util.getMD5String(dto.getPayId() + EnumVerificationKey.VIP.getValue());
}
/**
* 校验签名
* @param dto
* @return
*/
public static boolean checkSign(RefundDto dto) {
return MD5Util.getMD5String(dto.getPayId() + EnumVerificationKey.VIP.getValue()).equals(dto.getSign());
}
public static void main(String[] args) {
String sign = MD5Util.getMD5String("RVWU202305121022211042" + EnumVerificationKey.VIP.getValue());
System.out.println(sign);
System.out.println(MD5Util.getMD5String("RVWU202305121022211042" + EnumVerificationKey.VIP.getValue()).equals(sign));
}
}
Loading…
Cancel
Save