打印的日志:
2025-04-17 01:37:21.200 [http-nio-54321-exec-3] INFO c.i.wechat.web.QyWechatController - >>>wechat notify begin.requestBody is:{"summary":"商家转账单据终态通知","event_type":"MCHTRANSFER.BILL.FINISHED","create_time":"2025-04-17T01:36:30+08:00","resource":{"associated_data":"mch_payment","ciphertext":"aBguEt3BZGcjMHBFhsBoJagx/O8enipdhRr+EHJ2App8Vyw4XnRcaXrOA/Gt64J5G81cCTx5+huOXUlbUGxDSEfwOaU4nMUiPwDY6M7BYbJJtGmjCoID3daIjJK3W+XeHcbrKVd1BADR0vzQ8/fwLIP77HS/hEh5XMyGmBU+vCWgbZcWmST2rudiUeYK2hBgqXeKvbFj+OOPLB9zJGeW9dgZ42g6SH9uwynzLjzRMBn7b5VnGV9q0DtYI2mEgo1eI3EtLIixyocuIIsnUZguX2wjXSiFz4SOjKKafVWZSPLdiYlaulhO8o84au9H8Gn7tWinREixiIH2l93ZmTKq44xqMlrgq1FDrOLd89XACN9mZE5kdTVPvHm5mA3o5bLk80NftZ8iftspgFGFvua7PWhuc/GallL7Yi/sR/3oYg4kXatW3HdYSw==","original_type":"mch_payment","nonce":"yexRCij6Nxti","algorithm":"AEAD_AES_256_GCM"},"resource_type":"encrypt-resource","id":"aff21d5f-654d-597d-a132-cb914ebc6a42"}
2025-04-17 01:37:21.200 [http-nio-54321-exec-3] INFO c.i.wechat.web.QyWechatController - >>>wechatSignature is:W2N/w3OT/bKSl+LXFnr1WurdhtCgo+JxxiZ5rU0ncnT8A6fw2Wp0oy0cjTc2nZ2LVjwLDKAD6Dmua+iCvxC75ZNFN0BHji9R6hrzujvnxPe6us34zv9MZ7XeL4hilMOeIr+fSPn+96jSF78+xFQqUkX7gKk/Jto3hTYzjnR+MqIJVY61Ej0EVpUsEp/++QvXKPl3nr+iniOHwMVXm2Xoizf6jp51NpBxVOgRQZh8D07iEIhMNPqyK3aYtEngfMYeVMOn7qBYwjtIciLY2TPIPE58g84gvXHAtdwXWl6YS9QLkp2ruF0DT06HCxbFGhBNWXnhtAqXv1jApKrfc/gkvg==
2025-04-17 01:37:21.200 [http-nio-54321-exec-3] INFO c.i.wechat.web.QyWechatController - >>>wechatPaySerial is:3B52CC8B8323F3BAC723B40EF18AFD9E13D4DD3C
2025-04-17 01:37:21.200 [http-nio-54321-exec-3] INFO c.i.wechat.web.QyWechatController - >>>wechatpayNonce is:oEBAPZvavTqKNYhvT8TrwZCtIvaCYhCh
2025-04-17 01:37:21.200 [http-nio-54321-exec-3] INFO c.i.wechat.web.QyWechatController - >>>wechatTimestamp is:1744825041
2025-04-17 01:37:21.200 [http-nio-54321-exec-3] ERROR c.i.wechat.web.QyWechatController - sign verification failed
com.wechat.pay.java.core.exception.ValidationException: Processing WechatPay notification,signature verification failed,signType[WECHATPAY2-SHA256-RSA2048] serial[3B52CC8B8323F3BAC723B40EF18AFD9E13D4DD3C] message[1744825041
oEBAPZvavTqKNYhvT8TrwZCtIvaCYhCh
{"summary":"商家转账单据终态通知","event_type":"MCHTRANSFER.BILL.FINISHED","create_time":"2025-04-17T01:36:30+08:00","resource":{"associated_data":"mch_payment","ciphertext":"aBguEt3BZGcjMHBFhsBoJagx/O8enipdhRr+EHJ2App8Vyw4XnRcaXrOA/Gt64J5G81cCTx5+huOXUlbUGxDSEfwOaU4nMUiPwDY6M7BYbJJtGmjCoID3daIjJK3W+XeHcbrKVd1BADR0vzQ8/fwLIP77HS/hEh5XMyGmBU+vCWgbZcWmST2rudiUeYK2hBgqXeKvbFj+OOPLB9zJGeW9dgZ42g6SH9uwynzLjzRMBn7b5VnGV9q0DtYI2mEgo1eI3EtLIixyocuIIsnUZguX2wjXSiFz4SOjKKafVWZSPLdiYlaulhO8o84au9H8Gn7tWinREixiIH2l93ZmTKq44xqMlrgq1FDrOLd89XACN9mZE5kdTVPvHm5mA3o5bLk80NftZ8iftspgFGFvua7PWhuc/GallL7Yi/sR/3oYg4kXatW3HdYSw==","original_type":"mch_payment","nonce":"yexRCij6Nxti","algorithm":"AEAD_AES_256_GCM"},"resource_type":"encrypt-resource","id":"aff21d5f-654d-597d-a132-cb914ebc6a42"}
] sign[W2N/w3OT/bKSl+LXFnr1WurdhtCgo+JxxiZ5rU0ncnT8A6fw2Wp0oy0cjTc2nZ2LVjwLDKAD6Dmua+iCvxC75ZNFN0BHji9R6hrzujvnxPe6us34zv9MZ7XeL4hilMOeIr+fSPn+96jSF78+xFQqUkX7gKk/Jto3hTYzjnR+MqIJVY61Ej0EVpUsEp/++QvXKPl3nr+iniOHwMVXm2Xoizf6jp51NpBxVOgRQZh8D07iEIhMNPqyK3aYtEngfMYeVMOn7qBYwjtIciLY2TPIPE58g84gvXHAtdwXWl6YS9QLkp2ruF0DT06HCxbFGhBNWXnhtAqXv1jApKrfc/gkvg==]
at com.wechat.pay.java.core.notification.NotificationParser.validateRequest(NotificationParser.java:93)
at com.wechat.pay.java.core.notification.NotificationParser.parse(NotificationParser.java:49)
at com.infosky.wechat.web.MchTransferNotifyController.notifyHandle(MchTransferNotifyController.java:141)
at sun.reflect.GeneratedMethodAccessor543.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
=========================================代码=============================================
@PostMapping("/transfer")
public ResponseEntity notifyHandle(HttpServletRequest request) throws Exception {
BufferedReader reader = request.getReader();
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String myRequestBody = sb.toString();
logger.info(">>>wechat notify begin.requestBody is:" + myRequestBody );
String wechatSignature = request.getHeader("Wechatpay-Signature");
String wechatPaySerial = request.getHeader("Wechatpay-Serial");
String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
String wechatSignatureType = request.getHeader("Wechatpay-Signature-Type");
logger.info(">>>wechatSignature is:" + wechatSignature);
logger.info(">>>wechatPaySerial is:" + wechatPaySerial);
logger.info(">>>wechatpayNonce is:" + wechatpayNonce);
logger.info(">>>wechatTimestamp is:" + wechatTimestamp);
String wechatpaySerialNumber = notificationConfig.createVerifier().getSerialNumber();
logger.info("notificationConfig`s wechatpaySerialNumber is [{}] ", wechatpaySerialNumber);
logger.info("??? wechatPaySerial == wechatpaySerialNumber [{}] ", wechatPaySerial.equals(wechatpaySerialNumber));
// 构造 RequestParam
RequestParam requestParam = new RequestParam.Builder()
.serialNumber(wechatPaySerial)
.nonce(wechatpayNonce)
.signature(wechatSignature)
.timestamp(wechatTimestamp)
.body(myRequestBody)
.signType(wechatSignatureType)
.build();
// 初始化 NotificationParser
NotificationParser parser = new NotificationParser(notificationConfig);
try {
// 以支付通知回调为例,验签、解密并转换成 Transaction
Notification notification = parser.parse(requestParam, Notification.class);
logger.info(">>>notification is:" + notification);
String decryptString = new AesUtil(apiV3Key.getBytes()).decryptToString(notification.getResource().getAssociatedData().getBytes(),
notification.getResource().getNonce().getBytes(), notification.getResource().getCiphertext());
logger.info(">>>decryptString is:" + decryptString);
TransferBillsDecryptEntity decryptEntity = JSON.parseObject(decryptString, new TypeReference<TransferBillsDecryptEntity>() {
});
logger.info(">>>decryptEntity is:" + decryptEntity);
//TODO 回调业务逻辑处理 ...
} catch (ValidationException e) {
// 签名验证失败,返回 401 UNAUTHORIZED 状态码
logger.error("sign verification failed", e);
return new ResponseEntity<String>("{\"code\": \"SUCCESS\",\"message\": \"sign verification failed\"}", HttpStatus.UNAUTHORIZED);
} catch (Exception e) {
// 本地业务逻辑错误 或 解密失败
logger.error("ciphertext decrypt failed or other err:", e);
return new ResponseEntity<String>("{\"code\": \"SUCCESS\",\"message\": \"" + e.getMessage() + "\"}", HttpStatus.INTERNAL_SERVER_ERROR);
}
// 处理成功,返回 200 OK 状态码
return new ResponseEntity<String>("", HttpStatus.OK);
}
====================================配置类===========================================================
@Configuration
public class MchTransferConfig {
private static final Logger logger = LoggerFactory.getLogger(QyWechatController.class);
/**
* 商户号
*/
public static String merchantId = PropertiesConfig.readValue("merchantId");
/**
* 商户API私钥路径
*/
public static String privateKeyPath = PropertiesConfig.readValue("privateKeyPath");
/**
* 商户证书序列号
*/
public static String merchantSerialNumber = PropertiesConfig.readValue("merchantSerialNumber");
/**
* 商户APIV3密钥
*/
public static String apiV3Key = PropertiesConfig.readValue("apiV3Key");
/**
* 平台证书路径
*/
// public static String wechatPayCertificatePath = PropertiesConfig.readValue("wechatPayCertificatePath");
/**
* 通知配置
*
* @return
*/
@Bean
public NotificationConfig notificationConfig() {
// 自动下载平台证书
return new MyRSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
}
/**
* 商家转账配置
*
* @return
*/
@Bean
public Config config() {
// 自动下载平台证书
return new MyRSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
// 使用 com.wechat.pay.java.core.util
// 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
}
}
你手动能不能验证通过?