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