From 26cb0486f0772b425ab65fa1500c598511970d2e Mon Sep 17 00:00:00 2001 From: KKSU <15274802129@163.com> Date: Wed, 17 Jan 2024 13:59:02 +0800 Subject: [PATCH] fapiao --- src/main/java/cc/mrbird/febs/pay/service/impl/WxFaPiaoServiceImpl.java | 257 +++++++++++++++++++++++++++++--------------------- 1 files changed, 148 insertions(+), 109 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/pay/service/impl/WxFaPiaoServiceImpl.java b/src/main/java/cc/mrbird/febs/pay/service/impl/WxFaPiaoServiceImpl.java index fecfbbf..f35b58f 100644 --- a/src/main/java/cc/mrbird/febs/pay/service/impl/WxFaPiaoServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/pay/service/impl/WxFaPiaoServiceImpl.java @@ -20,6 +20,7 @@ import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler; import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest; import com.wechat.pay.contrib.apache.httpclient.util.AesUtil; +import com.wechat.pay.java.core.notification.Resource; import io.undertow.util.Certificates; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; @@ -37,12 +38,15 @@ import org.apache.http.util.EntityUtils; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; +import org.springframework.util.Base64Utils; +import org.springframework.web.bind.annotation.RequestBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.nio.charset.StandardCharsets; import java.security.*; +import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; @@ -206,77 +210,162 @@ } @Override - public Map<String, Object> fapiaoCallBack(HttpServletResponse response, HttpServletRequest request) { + public Map<String, Object> fapiaoCallBack(HttpServletRequest request, @RequestBody Map<String, Object> requestBody) throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { Map<String,Object> map = new HashMap<>(); - try { - BufferedReader br = request.getReader(); - String str = null; - StringBuilder sb = new StringBuilder(); - while ((str = br.readLine())!=null) { - sb.append(str); - } - // 构建request,传入必要参数 -// NotificationRequest requests = new NotificationRequest.Builder() -// .withSerialNumber(request.getHeader("Wechatpay-Serial")) -// .withNonce(request.getHeader("Wechatpay-Nonce")) -// .withTimestamp(request.getHeader("Wechatpay-Timestamp")) -// .withSignature(request.getHeader("Wechatpay-Signature")) -// .withBody(String.valueOf(sb)) -// .build(); - log.info("微信电子发票回调接口...."+request.getHeader("Wechatpay-Serial")); - log.info("微信电子发票回调接口...."+request.getHeader("Wechatpay-Nonce")); - log.info("微信电子发票回调接口...."+request.getHeader("Wechatpay-Timestamp")); - log.info("微信电子发票回调接口...."+request.getHeader("Wechatpay-Signature")); + String signature = request.getHeader("Wechatpay-Signature"); + String timestamp = request.getHeader("Wechatpay-Timestamp"); + String nonce = request.getHeader("Wechatpay-Nonce"); + //平台证书序列号不是API证书序列号 + String serial = request.getHeader("Wechatpay-Serial"); + String body = com.alibaba.fastjson.JSONObject.toJSONString(requestBody); + log.info("头信息---签名:" + signature); + log.info("头信息---时间戳:" + timestamp); + log.info("头信息---随机字符:" + nonce); + log.info("头信息---平台证书序列号:" + serial); + log.info("获取到的body信息:" + body); + //验签 + boolean signCheck = verifySign(request, body); +// boolean signCheck = signCheck(timestamp, nonce, requestBody, signature); + log.info("验签结果:" + signCheck); + if (signCheck) { +// //解密参数 +// Resource resource = com.alibaba.fastjson.JSONObject.parseObject(com.alibaba.fastjson.JSONObject.toJSONString(requestBody.get("resource")), Resource.class); +// AesUtil aesUtil = new AesUtil(CommonParameters.apiV3Key.getBytes("utf-8")); +// String string = aesUtil.decryptToString(resource.getAssociated_data().getBytes("utf-8"), resource.getNonce().getBytes("utf-8"), resource.getCiphertext()); +// ComplaintInfo complaintInfo = JSONObject.parseObject(string, ComplaintInfo.class); +// //获取投诉详情 +// ComplaintDetail complaintDetail = CommonUtils.GetComplaintsInfo(complaintInfo.getComplaint_id()); +// data.put("code", "SUCCESS"); +// data.put("message", "成功"); +// return data; + try { + //解析请求体 +// Resource resource = com.alibaba.fastjson.JSONObject.parseObject(com.alibaba.fastjson.JSONObject.toJSONString(requestBody.get("resource")), Resource.class); + Notification notification = com.alibaba.fastjson.JSONObject.parseObject(String.valueOf(body),Notification.class); + log.info("微信电子发票回调接口....解析请求体:"+notification.toString()); + String decryptData = notification.getDecryptData();//可能是支付业务的回调数据 + log.info("微信电子发票回调接口....decryptData:"+notification.toString()); + Notification.Resource resource = notification.getResource();//电子发票的回调加密数据 + log.info("微信电子发票回调接口....resource:"+notification.toString()); - log.info("微信电子发票回调接口....body"+request.getHeader(String.valueOf(sb))); - //验签 -// NotificationHandler handler = new NotificationHandler(getVerifier(AppContants.WX_CARD_NUM), xcxProperties.getWecharpaySecretV3().getBytes(StandardCharsets.UTF_8)); - //解析请求体 -// Notification notification = handler.parse(requests); - Notification notification = com.alibaba.fastjson.JSONObject.parseObject(String.valueOf(sb),Notification.class); - log.info("微信电子发票回调接口....解析请求体:"+notification.toString()); - String decryptData = notification.getDecryptData();//可能是支付业务的回调数据 - log.info("微信电子发票回调接口....decryptData:"+notification.toString()); - Notification.Resource resource = notification.getResource();//电子发票的回调加密数据 - log.info("微信电子发票回调接口....resource:"+notification.toString()); + if ("FAPIAO.USER_APPLIED".equals(notification.getEventType())//用户发票抬头填写完成类型:FAPIAO.USER_APPLIED + && !"encryptresource".equals(notification.getResourceType())) {//通知的资源数据类型,确认成功通知为encryptresource。 + //解密 + AesUtil aesUtil = new AesUtil(xcxProperties.getWecharpaySecretV3().getBytes("utf-8")); + String decryptToString = aesUtil.decryptToString( + resource.getAssociatedData().getBytes("utf-8"), + resource.getNonce().getBytes("utf-8"), + resource.getCiphertext()); + log.info("微信电子发票回调接口....resource解密:"+decryptToString); - if ("FAPIAO.USER_APPLIED".equals(notification.getEventType())//用户发票抬头填写完成类型:FAPIAO.USER_APPLIED - && !"encryptresource".equals(notification.getResourceType())) {//通知的资源数据类型,确认成功通知为encryptresource。 - //解密 - AesUtil aesUtil = new AesUtil(xcxProperties.getWecharpaySecretV3().getBytes("utf-8")); - String decryptToString = aesUtil.decryptToString( - resource.getAssociatedData().getBytes("utf-8"), - resource.getNonce().getBytes("utf-8"), - resource.getCiphertext()); - log.info("微信电子发票回调接口....resource解密:"+decryptToString); + JSONObject parseObj = JSONUtil.parseObj(decryptToString); - JSONObject parseObj = JSONUtil.parseObj(decryptToString); + log.info("微信电子发票回调接口....resource解密-JSONObject:"+parseObj); - log.info("微信电子发票回调接口....resource解密-JSONObject:"+parseObj); - - String mchid = String.valueOf(parseObj.get("mchid")); - String fapiao_apply_id = String.valueOf(parseObj.get("fapiao_apply_id")); - String apply_time = String.valueOf(parseObj.get("apply_time")); - MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectByOrderNo(fapiao_apply_id); - if(ObjectUtil.isNotEmpty(mallOrderInfo)){ - //省略查询订单 - //此处处理业务 - map.put("code","SUCCESS"); - map.put("message","成功"); - //消息推送成功 - return map; + String mchid = String.valueOf(parseObj.get("mchid")); + String fapiao_apply_id = String.valueOf(parseObj.get("fapiao_apply_id")); + String apply_time = String.valueOf(parseObj.get("apply_time")); + MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectByOrderNo(fapiao_apply_id); + if(ObjectUtil.isNotEmpty(mallOrderInfo)){ + //省略查询订单 + //此处处理业务 + map.put("code","SUCCESS"); + map.put("message","成功"); + //消息推送成功 + return map; + } } + map.put("code","RESOURCE_NOT_EXISTS"); + map.put("message", "订单不存在"); + return map; + }catch (Exception e) { + e.printStackTrace(); } - map.put("code","RESOURCE_NOT_EXISTS"); - map.put("message", "订单不存在"); - return map; - }catch (Exception e) { - e.printStackTrace(); } map.put("code","FAIL"); map.put("message", "失败"); return map; } + +// /** +// * 验证签名 +// * +// * @param timestamp 微信平台传入的时间戳 +// * @param nonce 微信平台传入的随机字符串 +// * @param requestBody 微信平台传入的消息体 +// * @param signature 微信平台传入的签名 +// * @return +// * @throws NoSuchAlgorithmException +// * @throws SignatureException +// * @throws IOException +// * @throws InvalidKeyException +// */ +// public static boolean signCheck(String timestamp, String nonce, Map<String, Object> requestBody, String signature) throws NoSuchAlgorithmException, SignatureException, IOException, InvalidKeyException { +// //构造验签名串 +// String signatureStr = timestamp + "\n" + nonce + "\n" + com.alibaba.fastjson.JSONObject.toJSONString(requestBody) + "\n"; +// // 加载SHA256withRSA签名器 +// Signature signer = Signature.getInstance("SHA256withRSA"); +// // 用微信平台公钥对签名器进行初始化(调上一节中的获取平台证书方法) +// signer.initVerify(getCertificates()); +// // 把我们构造的验签名串更新到签名器中 +// signer.update(signatureStr.getBytes(StandardCharsets.UTF_8)); +// // 把请求头中微信服务器返回的签名用Base64解码 并使用签名器进行验证 +// boolean result = signer.verify(Base64Utils.decodeFromString(signature)); +// return result; +// } + + + /** + * 获取平台证书 + */ +// public static X509Certificate getCertificates() throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException { +// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); +// CloseableHttpClient httpClient = CommonUtils.httpClient(); +// //请求URL +// HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/certificates"); +// httpGet.setHeader("Accept", "application/json"); +// //生成签名 +// httpGet.setHeader("Authorization ", SignUtils.getSign("GET", HttpUrl.parse("https://api.mch.weixin.qq.com/v3/certificates"), "")); +// httpGet.setHeader("User-Agent", "https://zh.wikipedia.org/wiki/User_agent"); +// //完成签名并执行请求 +// CloseableHttpResponse response = httpClient.execute(httpGet); +// X509Certificate x509Certificate = null; +// try { +// int statusCode = response.getStatusLine().getStatusCode(); +// if (statusCode == 200) { //处理成功 +//// System.out.println("success,return body = " + EntityUtils.toString(response.getEntity())); +// CertificateVo certificateVo = JSONObject.parseObject(EntityUtils.toString(response.getEntity()), CertificateVo.class); +// for (Certificates certificates : certificateVo.getData()) { +// if (format.parse(certificates.getEffective_time()).before(new Date()) && format.parse(certificates.getExpire_time()).after(new Date())) { +// EncryptCertificate encrypt_certificate = certificates.getEncrypt_certificate(); +// //解密 +// AesUtil aesUtil = new AesUtil(CommonParameters.apiV3Key.getBytes("utf-8")); +// String pulicKey = aesUtil.decryptToString(encrypt_certificate.getAssociated_data().getBytes("utf-8"), encrypt_certificate.getNonce().getBytes("utf-8"), encrypt_certificate.getCiphertext()); +// +// //获取平台证书 +// final CertificateFactory cf = CertificateFactory.getInstance("X509"); +// +// ByteArrayInputStream inputStream = new ByteArrayInputStream(pulicKey.getBytes(StandardCharsets.UTF_8)); +// +// x509Certificate = (X509Certificate) cf.generateCertificate(inputStream); +// } +// } +// return x509Certificate; +// } else if (statusCode == 204) { //处理成功,无返回Body +// System.out.println("success"); +// return x509Certificate; +// } else { +// System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity())); +// return x509Certificate; +// } +// } catch (GeneralSecurityException | ParseException e) { +// e.printStackTrace(); +// return null; +// } finally { +// response.close(); +// CommonUtils.after(httpClient); +// } +// } /** * 功能描述: 验证签名 @@ -357,56 +446,6 @@ } return verifier; } - - /** - * 获取平台证书 - */ -// public static X509Certificate getCertificates() throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException { -// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); -// CloseableHttpClient httpClient = HttpClients.createDefault(); -// //请求URL -// HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/certificates"); -// httpGet.setHeader("Accept", "application/json"); -// //生成签名 -// httpGet.setHeader("Authorization ", SignUtils.getSign("GET", HttpUrl.parse("https://api.mch.weixin.qq.com/v3/certificates"), "")); -// httpGet.setHeader("User-Agent", "https://zh.wikipedia.org/wiki/User_agent"); -// //完成签名并执行请求 -// CloseableHttpResponse response = httpClient.execute(httpGet); -// X509Certificate x509Certificate = null; -// try { -// int statusCode = response.getStatusLine().getStatusCode(); -// if (statusCode == 200) { //处理成功 -//// System.out.println("success,return body = " + EntityUtils.toString(response.getEntity())); -// CertificateVo certificateVo = JSONObject.parseObject(EntityUtils.toString(response.getEntity()), CertificateVo.class); -// for (Certificates certificates : certificateVo.getData()) { -// if (format.parse(certificates.getEffective_time()).before(new Date()) && format.parse(certificates.getExpire_time()).after(new Date())) { -// EncryptCertificate encrypt_certificate = certificates.getEncrypt_certificate(); -// //解密 -// AesUtil aesUtil = new AesUtil(CommonParameters.apiV3Key.getBytes("utf-8")); -// String pulicKey = aesUtil.decryptToString(encrypt_certificate.getAssociated_data().getBytes("utf-8"), encrypt_certificate.getNonce().getBytes("utf-8"), encrypt_certificate.getCiphertext()); -// //获取平台证书 final CertificateFactory cf = CertificateFactory.getInstance("X509"); -// -// ByteArrayInputStream inputStream = new ByteArrayInputStream(pulicKey.getBytes(StandardCharsets.UTF_8)); -// -// x509Certificate = (X509Certificate) cf.generateCertificate(inputStream); -// } -// } -// return x509Certificate; -// } else if (statusCode == 204) { //处理成功,无返回Body -// System.out.println("success"); -// return x509Certificate; -// } else { -// System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity())); -// return x509Certificate; -// } -// } catch (GeneralSecurityException | ParseException e) { -// e.printStackTrace(); -// return null; -// } finally { -// response.close(); -// CommonUtils.after(httpClient); -// } -// } /** -- Gitblit v1.9.1