|
|
@@ -161,70 +161,16 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
wxHttpClient = (OkHttpClientAdapter) new DefaultHttpClientBuilder().newInstance().config(config).build();
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- /**
|
|
|
- * 处理微信回调信息,验签解密
|
|
|
- *
|
|
|
- * @param request
|
|
|
- * @return array[0] RequestParam 请求参数
|
|
|
- * array[1] NotificationParser 通知解析器
|
|
|
- * array[2] nonce 随机数
|
|
|
- */
|
|
|
- @SneakyThrows
|
|
|
- Object[] handleWxNotify(HttpServletRequest request) {
|
|
|
- var no = RandomUtil.randomInt(1000, 9999);
|
|
|
- var signature = request.getHeader("Wechatpay-Signature");
|
|
|
- var serial = request.getHeader("Wechatpay-Serial");
|
|
|
- var nonce = request.getHeader("Wechatpay-Nonce");
|
|
|
- var timestamp = request.getHeader("Wechatpay-Timestamp");
|
|
|
- var signatureType = request.getHeader("Wechatpay-Signature-Type");
|
|
|
-
|
|
|
- LOGGER.info("微信支付回调{}:\n Request参数:\n signature:{},serial:{},nonce:{},timestamp:{},signatureType:{}", no, signature, serial, nonce, timestamp, signatureType);
|
|
|
-
|
|
|
- // request中获取body
|
|
|
-// BufferedReader br = request.getReader();
|
|
|
-// String str;
|
|
|
-// var requestBody = new StringBuilder();
|
|
|
-// while ((str = br.readLine()) != null) {
|
|
|
-// requestBody.append(str);
|
|
|
-// }
|
|
|
-
|
|
|
- ServletInputStream inputStream = request.getInputStream();
|
|
|
- ByteArrayOutputStream result = new ByteArrayOutputStream();
|
|
|
- byte[] buffer = new byte[1024];
|
|
|
- for (int lenght; (lenght = inputStream.read(buffer)) != -1; ) {
|
|
|
- result.write(buffer, 0, lenght);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- LOGGER.info("微信支付回调{}:\nBody数据:\n{}", no, result);
|
|
|
-
|
|
|
- // 构造 RequestParam
|
|
|
- RequestParam requestParam = new RequestParam.Builder()
|
|
|
- .serialNumber(serial)
|
|
|
- .nonce(nonce) // 随机数
|
|
|
- .signature(signature)
|
|
|
- .timestamp(timestamp)
|
|
|
- .body(result.toString(StandardCharsets.UTF_8))
|
|
|
- .build();
|
|
|
- LOGGER.info("微信支付回调{}:构造 RequestParam完毕", no);
|
|
|
-
|
|
|
- // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
|
|
|
- // 初始化 NotificationParser
|
|
|
- NotificationParser parser = new NotificationParser((NotificationConfig) config);
|
|
|
- return new Object[]{requestParam, parser, no};
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
* 回调签名验证失败排查指引 (body中字段顺序变化造成验签失败是个大坑)
|
|
|
* https://developers.weixin.qq.com/community/pay/article/doc/0004a879f60928d89340b8b9f64c13
|
|
|
* https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient/issues/152
|
|
|
+ *
|
|
|
* @param request
|
|
|
* @return
|
|
|
*/
|
|
|
@SneakyThrows
|
|
|
- Object[] handleWxNotify2(HttpServletRequest request) {
|
|
|
+ Object[] handleWxNotify(HttpServletRequest request) {
|
|
|
var no = RandomUtil.randomInt(1000, 9999);
|
|
|
var signature = request.getHeader("Wechatpay-Signature");
|
|
|
var serial = request.getHeader("Wechatpay-Serial");
|
|
|
@@ -232,6 +178,11 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
var timestamp = request.getHeader("Wechatpay-Timestamp");
|
|
|
var signatureType = request.getHeader("Wechatpay-Signature-Type");
|
|
|
|
|
|
+ // 应对探测流量
|
|
|
+ if (signature.contains("SIGNTEST")) {
|
|
|
+ throw new BusinessException("接收到签名探测流量");
|
|
|
+ }
|
|
|
+
|
|
|
LOGGER.info("微信支付回调{}:\n Request参数:\n signature:{},serial:{},nonce:{},timestamp:{},signatureType:{}", no, signature, serial, nonce, timestamp, signatureType);
|
|
|
|
|
|
ServletInputStream inputStream = request.getInputStream();
|
|
|
@@ -337,9 +288,8 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
public ResponseEntity<Object> wxNotify(HttpServletRequest request) {
|
|
|
|
|
|
- var notifyRes = handleWxNotify(request);
|
|
|
-
|
|
|
try {
|
|
|
+ var notifyRes = handleWxNotify(request);
|
|
|
// 以支付通知回调为例,验签、解密并转换成 Transaction
|
|
|
Transaction transaction = ((NotificationParser) notifyRes[1]).parse((RequestParam) notifyRes[0], Transaction.class);
|
|
|
LOGGER.info("微信支付回调{}:验签解密完毕,数据:\n{}", notifyRes[2], transaction);
|
|
|
@@ -394,16 +344,20 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
activityService.handleRechargeActivity(chargingOrder.getUserId(), transaction.getAmount().getTotal());
|
|
|
}
|
|
|
|
|
|
-
|
|
|
return ResponseEntity.status(HttpStatus.OK).build();
|
|
|
|
|
|
} else {
|
|
|
LOGGER.error("微信支付通知处理异常,资金流水为空,回调信息:{}", transaction);
|
|
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("code", HttpStatus.INTERNAL_SERVER_ERROR, "message", "资金流水为空"));
|
|
|
}
|
|
|
- } catch (ValidationException e) {
|
|
|
- // 签名验证失败,返回 401 UNAUTHORIZED 状态码
|
|
|
- LOGGER.error("微信支付通知验签失败", e);
|
|
|
+ } catch (Exception e) {
|
|
|
+ if (e instanceof ValidationException) {
|
|
|
+ // 签名验证失败,返回 401 UNAUTHORIZED 状态码
|
|
|
+ LOGGER.error("微信支付通知验签失败", e);
|
|
|
+ }
|
|
|
+ if (e instanceof BusinessException) {
|
|
|
+ LOGGER.error("业务异常", e);
|
|
|
+ }
|
|
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("code", HttpStatus.UNAUTHORIZED, "message", "验签失败"));
|
|
|
}
|
|
|
}
|
|
|
@@ -851,7 +805,7 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
* 微信开票结果通知
|
|
|
* event_tyoe为FAPIAO.ISSUED
|
|
|
*
|
|
|
- * @param request
|
|
|
+ * @param notifyRes
|
|
|
* @return
|
|
|
*/
|
|
|
@Override
|
|
|
@@ -880,7 +834,7 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
*/
|
|
|
@Override
|
|
|
public void invoiceNotify(HttpServletRequest request) {
|
|
|
- var notifyRes = handleWxNotify2(request);
|
|
|
+ var notifyRes = handleWxNotify(request);
|
|
|
var requestParam = (RequestParam) notifyRes[0];
|
|
|
Notification notification = JSONObject.parseObject(requestParam.getBody(), Notification.class);
|
|
|
switch (notification.getEventType()) {
|