• 首页
  • 邻居
  • 关于
  • 归档
  • 搜索
  • 夜间模式
    ©2020-2026  我的学习笔记 Theme by OneBlog

    我的学习笔记博客

    搜索
    标签
    # 随笔 # Java # 教程 # openwrt # Mysql # SQL # 爬虫 # post # Js调优 # MAVEN
  • 首页>
  • 随笔>
  • 正文
  • 微信小程序集成b2b交易代码

    2025年04月21日 1.1 k 阅读 0 评论 32882 字

    vue:

    // 微信支付,将参数传后端获取数据掉起微信支付
                            wxPayOrder(orderData).then(response => {
                                let params = response.data
                                wx.requestCommonPayment({
                                    signData: params.signData,
                                    mode: params.mode,
                                    paySig: params.paySig,
                                    signature: params.signature,
                                    success(res) {
                                        console.log('支付成功', res);
                                        this.paySuccess()
                                    },
                                    fail(res) {
                                        console.log('支付失败,res', res);
                                        uni.showToast({
                                            title: '支付失败,如果您已支付,请勿反复支付',
                                            icon: 'none'
                                        })
                                    }
                                });

    java

        //微信支付下单统一参数封装
                Map<String, Object> payParams = Maps.newHashMapWithExpectedSize(CommonConstants.INTEGER_TYPE.TYPE_EIGHT);
    
                payParams.put("mchid", wxConfig.getB2bMchId());
    
                payParams.put("description", request.getOrderName());
                payParams.put("out_trade_no", DateUtil.getDateline() + "b2b" + request.getOutTradeNo());
                Map<String, Object> outTradeNoParams = Maps.newHashMapWithExpectedSize(CommonConstants.INTEGER_TYPE.TYPE_ONE);
                outTradeNoParams.put("out_trade_no", request.getOutTradeNo());
                payParams.put("attach", JsonUtils.toJsonString(outTradeNoParams));
                Map<String, Object> amountMap = Maps.newHashMapWithExpectedSize(CommonConstants.INTEGER_TYPE.TYPE_ONE);
                amountMap.put("order_amount", MoneyUtils.yuanToFen(request.getFee()));
                payParams.put("amount", amountMap);
                payParams.put("env", 0);
                String uri = "requestCommonPayment";
                String url2 = uri + "&" + JSON.toJSONString(payParams);
    
                Map<String, Object> connect = remoteConnectService.queryConnect(
                    LoginHelper.getUserId() + "", SourceEnum.WECHAT_MP_OPEN_ID.name()
                );
                if (connect == null) {
                    log.error("未获取到用户{}:{}登录信息", LoginHelper.getUserId() + "", SourceEnum.WECHAT_MP_OPEN_ID.name());
                    return null;
                }
    
                String paramsStr = JSON.toJSONString(payParams);
                log.info("统一下单API,支付参数:{}", paramsStr);
    
                PayResponse payResponse = new PayResponse();
                payResponse.setSignData(paramsStr);
                payResponse.setMode(wxConfig.getB2bMode());
                payResponse.setPaySig(HmacSha256Util.hmacSha256Hex(wxConfig.getB2bAppKey(), url2));
                payResponse.setSignature(HmacSha256Util.hmacSha256Hex(connect.get("sessionKey").toString(), paramsStr));
    
                log.info("统一下单最后返回支付参数:{}", JSON.toJSONString(payResponse));

    编码工具类:

    package com.honghan.common.core.utils;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import java.nio.charset.StandardCharsets;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    
    public class HmacSha256Util {
        public static String hmacSha256Hex(String key, String data) {
            try {
                Mac sha256Hmac = Mac.getInstance("HmacSHA256");
                SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
                sha256Hmac.init(secretKey);
    
                byte[] hashBytes = sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
                return bytesToHex(hashBytes);
            } catch (NoSuchAlgorithmException | InvalidKeyException e) {
                throw new RuntimeException("Error while generating HMAC-SHA256", e);
            }
        }
    
        private static String bytesToHex(byte[] bytes) {
            StringBuilder hexString = new StringBuilder();
            for (byte b : bytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1)
                    hexString.append('0');
                hexString.append(hex);
            }
            return hexString.toString();
        }
    
        // Example usage:
        public static void main(String[] args) {
            String sessionKey = "yourSessionKey";
            String signData = "yourSignData";
            String signature = hmacSha256Hex(sessionKey, signData);
            System.out.println("Signature: " + signature);
        }
    }
    

    b2b支付回调通知已经请求加解密方法:

    package com.honghan.trade.controller.pay;
    
    import cn.hutool.core.date.DateTime;
    import cn.hutool.core.net.URLDecoder;
    import cn.hutool.json.JSONUtil;
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.alibaba.fastjson.TypeReference;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.honghan.common.core.constant.CommonConstants;
    import com.honghan.common.core.constant.Constants;
    import com.honghan.common.core.domain.ResultResponse;
    import com.honghan.common.core.enums.OrderStatus;
    import com.honghan.common.core.exception.ServiceException;
    import com.honghan.common.core.utils.HttpUtils;
    import com.honghan.common.core.utils.TimeUtils;
    import com.honghan.common.core.utils.ajax.AjaxUtils;
    import com.honghan.common.core.utils.copy.CopyUtils;
    import com.honghan.mall.api.RemoteProductSkuStockService;
    import com.honghan.site.api.RemoteCompanyService;
    import com.honghan.store.api.RemoteStoreOrderService;
    import com.honghan.store.api.RemoteStoreStockService;
    import com.honghan.system.api.RemoteSysConfigService;
    import com.honghan.trade.api.call.PaySuccessCallback;
    import com.honghan.trade.api.call.ResultWechatBack;
    import com.honghan.trade.api.domain.PaymentSuccessParamsVO;
    import com.honghan.trade.api.domain.TradeOrder;
    import com.honghan.trade.api.domain.pay.PayResponse;
    import com.honghan.trade.config.pay.config.WxConfig;
    import com.honghan.trade.config.pay.sign.WechatPayValidator;
    import com.honghan.trade.domain.vo.TradeOrderVO;
    import com.honghan.trade.payment.RefundLogService;
    import com.honghan.trade.payment.entity.RefundLog;
    import com.honghan.trade.payment.entity.enums.PaymentMethodEnum;
    import com.honghan.trade.payment.param.PaymentSuccessParams;
    import com.honghan.trade.service.*;
    import com.honghan.trade.service.pay.AliPayService;
    import com.honghan.trade.service.pay.call.OrderPayCallback;
    import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
    import lombok.extern.slf4j.Slf4j;
    import me.chanjar.weixin.common.util.crypto.PKCS7Encoder;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.dubbo.config.annotation.DubboReference;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.annotation.Resource;
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.text.SimpleDateFormat;
    import java.util.*;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 订单回调
     */
    @Slf4j
    @RestController
    @RequestMapping("/order/notify")
    public class TradeOrderNotifyController {
    
        private final ReentrantLock lock = new ReentrantLock();
        @Resource
        private TradeOrderService tradeOrderService;
        @Resource
        private TradeOrderProductService tradeOrderProductService;
        @Resource
        private TradeMessageService tradeMessageService;
        @Resource
        private IBillOrderService billOrderService;
        @Resource
        private ISubOrderService subOrderService;
        @Resource
        private PaySuccessCallback paySuccessCallback;
        @Resource
        private AliPayService aliPayService;
        @Resource
        private TradeMatchService tradeMatchService;
        @Resource
        private TradeMatchDetailService tradeMatchDetailService;
        @Resource
        private WxConfig wxConfig;
        @Resource
        private Verifier verifier;
        @Resource
        private IPaymentOrderService paymentOrderService;
        @Resource
        private OrderPayCallback orderPayCallback;
        @DubboReference
        private RemoteCompanyService companyService;
        @DubboReference
        private RemoteStoreStockService remoteStoreStockService;
        @DubboReference
        private RemoteCompanyService remoteCompanyService;
        @DubboReference
        private RemoteSysConfigService remoteSysConfigService;
        @DubboReference
        private RemoteStoreOrderService remoteStoreOrderService;
        @DubboReference
        private RemoteProductSkuStockService remoteProductSkuStockService;
        /**
         * 退款日志
         */
        @Autowired
        private RefundLogService refundLogService;
    
        /**
         * 支付宝回调接口
         */
        @PostMapping("/alipayNotify")
        public void aliPayNotify(HttpServletRequest request, HttpServletResponse response) {
            ResultResponse<PayResponse> result = aliPayService.asyncNotify(request, paySuccessCallback);
            if (result.getCode() == Constants.SUCCESS) {
                AjaxUtils.renderText(response, CommonConstants.SUCCESS);
            } else {
                AjaxUtils.renderText(response, CommonConstants.FAIL);
            }
        }
    
    
        /**
         * 微信回调接口
         */
        @PostMapping("/wxPayNotify")
        public Map<String, String> wxPayNotify(HttpServletRequest request, HttpServletResponse response) {
            String orderNo = "";
            try {
                //处理通知参数
                String body = HttpUtils.readData(request);
                log.info("微信支付回调参数:{}", body);
                //转换为Map
                Map<String, Object> bodyMap = JSONObject.parseObject(body, new TypeReference<Map<String, Object>>() {
                });
    
                //微信的通知ID(通知的唯一ID)
                String notifyId = bodyMap.get("id").toString();
    
                //构造验证签名信息
                WechatPayValidator wxCheckSign = new WechatPayValidator(verifier, notifyId, body);
                if (!wxCheckSign.validate(request)) {
                    return ResultWechatBack.falseMsg(response);
                }
                if (lock.tryLock(6, TimeUnit.SECONDS)) {
                    //解密resource中的通知数据
                    String resource = bodyMap.get("resource").toString();
                    Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wxConfig.getApiV3Key(), 1);
                    //解密后返回相关订单详情
                    log.info("微信支付回调解密后返回相关订单详情---{}", resourceMap);
                    orderNo = resourceMap.get("out_trade_no").toString();
                    String transactionId = resourceMap.get("transaction_id").toString();
                    String tradeState = resourceMap.get("trade_state").toString();
    
                    if (StringUtils.equals(WxConfig.SUCCESS, tradeState)) {
                        String _payTime = resourceMap.get("success_time").toString();
                        DateTime dateTime = new DateTime(_payTime);
                        //转换成Date对象
                        Date timeDate = dateTime.toJdkDate();
    
                        String payParamStr = resourceMap.get("attach").toString();
                        String payParamJson = URLDecoder.decode(payParamStr, StandardCharsets.UTF_8);
                        //PayParam payParam = JSONUtil.toBean(payParamJson, PayParam.class);
    
    
                        String tradeNo_ = resourceMap.get("transaction_id").toString();
                        Double totalAmount = null;
    
                        PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams(
                            PaymentMethodEnum.WECHAT.name(),
                            tradeNo_,
                            totalAmount,
                            null
                        );
    
                        paySuccessCallback.doWhilePaySuccess(CopyUtils.copy(paymentSuccessParams, PaymentSuccessParamsVO.class), orderNo, transactionId, timeDate);
    
    //                    if(orderNo.startsWith("Y")) {
    //                        //购物车下的订单
    //                        List<SubOrder> subOrder = subOrderService.getOrderNos(orderNo);
    //                        List<String> orderNoList = subOrder.stream().map(SubOrder::getCarOrderNo).collect(Collectors.toList());
    //                        List<TradeOrder> tradeOrders = tradeOrderService.getByPayOrder(orderNoList);
    //                        for (TradeOrder tradeOrder : tradeOrders) {
    //                            if (tradeOrder.getType().equals(OrderType.MALL.getValue())) {
    //                                Asserts.isTrue(tradeOrder.getStatus().equals(OrderStatus.CONFIRMED.getValue()), "订单状态不是待付款状态!");
    //                                tradeOrder.setStatus(OrderStatus.PAYED.getValue());
    //                            } else if (tradeOrder.getType().equals(OrderType.MALL_MATCH.getValue())) {
    //                                Asserts.isTrue(tradeOrder.getStatus().equals(OrderStatus.CONFIRMED.getValue()), "订单状态不是待付款状态!");
    //                                tradeOrder.setStatus(OrderStatus.COUNT.getValue());
    //                            }
    //                            tradeOrder.setPayTime(TimeUtils.getNowDate());
    //                            orderPayCallback.paySuccess(orderNo, transactionId, tradeOrder);
    //                        }
    //                    }else if (orderNo.startsWith("W") || orderNo.startsWith("F")) {
    //                        PaymentOrder payMentOrder = paymentOrderService.queryOrderNo(orderNo);
    //                        Asserts.isTrue(payMentOrder.getStatus().equals(0), "付款单状态不是待付款状态!");
    //                        TradeOrder tradeOrder =  tradeOrderService.getById(payMentOrder.getOriginalOrderId());
    //                        payMentOrder.setPayType(tradeOrder.getPayType());
    //                        payMentOrder.setStatus(PaymentStatusEnum.FINISH.getValue());
    //                        payMentOrder.setPayTime(TimeUtils.getNowDate());
    //                        payMentOrder.setPayNo(transactionId);
    //                        boolean updateById = paymentOrderService.updateById(payMentOrder);
    //                        if (updateById) {
    //                            Integer total = payMentOrder.getTotal();
    //                            List<PaymentOrder> paymentOrders = paymentOrderService.queryOriginalOrderId(payMentOrder.getOriginalOrderId(), null);
    //                            long payAmountNum = paymentOrders.stream().filter(paymentOrder-> paymentOrder.getStatus() == 1).count();
    //                            //付款方式 1 先款后货 2 先付订金 后付尾款   3 先货后款
    //                            if(total == 1 && payMentOrder.getPaymentType() == 3) {
    //                                //付完钱直接完成
    //                                tradeOrder.setStatus(OrderStatus.COUNT.getValue());
    //                            }else if(total == 2){
    //                                if(payMentOrder.getRemark().equals(PaymentPayTypeEnum.FIRST_PAYMENT.getValue())){
    //                                    tradeOrder.setIfPickUp(1);
    //                                    tradeOrder.setStatus(OrderStatus.PART_PAYED.getValue());
    //                                } else {
    //                                    tradeOrder.setStatus(OrderStatus.COUNT.getValue());
    //                                }
    //                            }else {
    //                                tradeOrder.setIfPickUp(1);
    //                                tradeOrder.setStatus(OrderStatus.COUNT.getValue());
    //                            }
    //                            boolean paymentUpdateById = tradeOrderService.updateById(tradeOrder);
    //                            if(paymentUpdateById){
    //                                tradeOrderProductService.batchUpdateProductSaleNum(tradeOrder.getId());
    //                            }
    //                        }
    //                    }else {
    //                        LambdaQueryWrapper<TradeOrder> queryWrapper = Wrappers.lambdaQuery();
    //                        queryWrapper.eq(TradeOrder::getIdentifier, orderNo);
    //                        queryWrapper.last("LIMIT 1");
    //                        TradeOrder tradeOrder = tradeOrderService.getOne(queryWrapper);
    //                        Asserts.isTrue(tradeOrder.getStatus().equals(OrderStatus.CONFIRMED.getValue()), "订单状态不是待付款状态!");
    //                        tradeOrder.setIfPickUp(1);
    //                        tradeOrder.setStatus(OrderStatus.PAYED.getValue());
    //                        orderPayCallback.paySuccess(orderNo, transactionId, tradeOrder);
    //                    }
                        //成功应答 响应微信
                        log.info("微信支付回调成功----商户订单号:{}", orderNo);
                        return ResultWechatBack.trueMsg(response);
                    } else {
                        log.warn("微信支付回调状态并不是SUCCESS:{}", resourceMap);
                        return ResultWechatBack.falseMsg(response);
                    }
                }
            } catch (Exception e) {
                log.error("微信支付回调处理失败, orderNo = " + orderNo, e);
                return ResultWechatBack.falseMsg(response);
            } finally {
                //要主动释放锁
                lock.unlock();
            }
            return ResultWechatBack.trueMsg(response);
        }
    
    
        private static final String TOKEN = "xxx"; // Token
        private static final String ENCODING_AES_KEY = "xxx"; // EncodingAESKey
        private static final String APPID = "xxx"; // 小程序Appid
    
        /**
         * 微信消息推送
         */
        @RequestMapping("/callback")
        public void callback(HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException {
    
            // 从 URL 参数中获取
            String signature = request.getParameter("signature");
            String timestamp = request.getParameter("timestamp");
            String nonce = request.getParameter("nonce");
            String echostr = request.getParameter("echostr");
    
            if (StringUtils.isNotBlank(echostr) && checkSignature(signature, timestamp, nonce)) {
                // 返回 echostr 表示验证通过
                httpServletResponse.getWriter().write(echostr);
                return null;
            }
            String msgSignature = request.getParameter("msg_signature");
            String encryptType = request.getParameter("encrypt_type"); // "aes" 是加密类型
    
            // 打印请求的 URL 参数
            System.out.println("signature: " + signature);
            System.out.println("timestamp: " + timestamp);
            System.out.println("nonce: " + nonce);
            System.out.println("msg_signature: " + msgSignature);
            System.out.println("encrypt_type: " + encryptType);
    
            // 从请求体中获取 JSON 数据(Encrypt 字段)
            StringBuilder body = new StringBuilder();
            try (BufferedReader reader = request.getReader()) {
                String line;
                while ((line = reader.readLine()) != null) {
                    body.append(line);
                }
            }
    
            String jsonBody = body.toString();
            System.out.println("Request Body (JSON): " + jsonBody);
    
            // 解析 JSON 数据中的 Encrypt 字段
            String encrypt = parseEncryptField(jsonBody);
            System.out.println("Encrypt: " + encrypt);
    
            // 校验 msg_signature 签名是否正确
            if (!checkMsgSignature(msgSignature, timestamp, nonce, encrypt)) {
                return ResponseEntity.status(400).body("Signature verification failed!");
            }
    
            // 解密消息体中的 Encrypt 内容
            String decryptedMessage = decryptMessage(encrypt); // 解密消息
            System.out.println("Decrypted message: " + decryptedMessage);
    
            cn.hutool.json.JSONObject entries = JSONUtil.parseObj(decryptedMessage);
    
            if (!entries.getStr("appid").equals(APPID)) {
                throw new RuntimeException("AppId 不匹配,非法请求");
            }
            entries = entries.getJSONObject("msg");
            String event = entries.getStr("Event");
            if (event.equalsIgnoreCase("retail_pay_notify")) {
                String orderNo = "";
                String transactionId = entries.getStr("order_id").toString();
                String tradeState = entries.getStr("pay_status").toString();
    
                if (StringUtils.equalsIgnoreCase("ORDER_PAY_SUCC", tradeState)) {
                    String _payTime = entries.getStr("pay_time").toString();
                    DateTime dateTime = new DateTime(_payTime);
                    //转换成Date对象
                    Date timeDate = dateTime.toJdkDate();
    
                    String payParamStr = entries.getStr("attach").toString();
                    orderNo = JSONUtil.parseObj(payParamStr).getStr("out_trade_no");
                    if (orderNo.contains("b2b")) {
                        orderNo = orderNo.split("b2b")[1];
                    }
                    String tradeNo_ = entries.getStr("order_id").toString();
                    Double totalAmount = null;
    
                    PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams(
                        PaymentMethodEnum.WECHAT.name(),
                        tradeNo_,
                        totalAmount,
                        null
                    );
                    try {
                        paySuccessCallback.doWhilePaySuccess(CopyUtils.copy(paymentSuccessParams, PaymentSuccessParamsVO.class), orderNo, transactionId, timeDate);
                    } catch (Exception e) {
                        log.error("微信支付回调处理失败, orderNo = " + orderNo, e);
                    }
                    //成功应答 响应微信
                    log.info("微信支付回调成功----商户订单号:{}", orderNo);
                } else {
                    log.warn("微信支付回调状态并不是SUCCESS:{}", tradeState);
                }
            } else if (event.equalsIgnoreCase("retail_refund_notify")) {
                String orderNo = "";
                String transactionId = entries.getStr("order_id").toString();
                String refundId = entries.getStr("refund_id").toString();
                orderNo = entries.getStr("out_trade_no");
                if (orderNo.contains("b2b")) {
                    orderNo = orderNo.split("b2b")[1];
                }
                String outRefundNo = entries.getStr("out_refund_no").toString();//商户退款单号
                String refundStatus = entries.getStr("refund_status").toString();//微信退款状态
                if (StringUtils.isNotBlank(refundStatus) && StringUtils.equalsIgnoreCase("REFUND_SUCC", refundStatus)) {
                    TradeOrderVO tradeOrderVO = tradeOrderService.selectVoByOutRefundNo(outRefundNo);
                    if (Objects.isNull(tradeOrderVO)) {
                        log.warn("微信该笔订单号商家不存在,退款订单号:{}", outRefundNo);
                        new ServiceException("微信该笔订单号商家不存在,退款订单号:" + outRefundNo);
                    }
                    String successTime = entries.getStr("refund_time").toString();//微信退款成功时间
                    TradeOrder tradeOrder = new TradeOrder();
                    tradeOrder.setId(tradeOrderVO.getId());
                    tradeOrder.setStatus(OrderStatus.CANCELLED.getValue());
                    try {
                        if (StringUtils.isNotBlank(successTime)) {
                            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
                            Date date = formatter.parse(successTime);
                            Date refundSuccessTime = TimeUtils.parseDate(TimeUtils.format(date, CommonConstants.DATE.FORMAT_DEFAULT), CommonConstants.DATE.FORMAT_DEFAULT);
                            tradeOrder.setRefundTime(refundSuccessTime);
                        } else {
                            tradeOrder.setRefundTime(TimeUtils.getNowDate());
                        }
                    } catch (Exception e) {
                        log.error("商城订单-微信退款回调处理失败, orderNo = " + orderNo, e);
                    }
    
                    tradeOrderService.updateById(tradeOrder);
                    log.info("商城订单微信退款回调成功success----商户订单号:{}", orderNo);
    
                    RefundLog refundLog = refundLogService.getOne(new LambdaQueryWrapper<RefundLog>().eq(RefundLog::getPaymentReceivableNo,
                        transactionId));
                    if (refundLog != null) {
                        refundLog.setIsRefund(true);
                        refundLog.setReceivableNo(refundId);
                        refundLogService.saveOrUpdate(refundLog);
                    }
                }
            }
    
            // 处理解密后的消息逻辑(根据需求)
         //   String responseMessage = "{\"demo_resp\":\"good luck\"}";
    
            // 构造回包
         //   String response = createResponse(responseMessage);
    
            httpServletResponse.getWriter().write("success");
        }
    
        /**
         * 验证微信签名
         *
         * @param signature 微信传来的签名
         * @param timestamp 微信传来的时间戳
         * @param nonce     微信传来的随机数
         * @return 是否是合法请求
         */
        public static boolean checkSignature(String signature, String timestamp, String nonce) {
            try {
                String[] arr = new String[]{TOKEN, timestamp, nonce};
                // 1. 字典序排序
                Arrays.sort(arr);
                // 2. 拼接成一个字符串
                StringBuilder content = new StringBuilder();
                for (String s : arr) {
                    content.append(s);
                }
                // 3. SHA1加密
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                byte[] digest = md.digest(content.toString().getBytes());
                // 4. 转成十六进制字符串
                StringBuilder hexStr = new StringBuilder();
                for (byte b : digest) {
                    String shaHex = Integer.toHexString(b & 0xFF);
                    if (shaHex.length() < 2) {
                        hexStr.append(0);
                    }
                    hexStr.append(shaHex);
                }
                // 5. 比较签名
                return hexStr.toString().equals(signature);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 解析请求体中的 Encrypt 字段
         */
        private String parseEncryptField(String jsonBody) {
            try {
                JSONObject jsonObject = JSON.parseObject(jsonBody);
                return jsonObject.getString("Encrypt");
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * 校验 msg_signature 签名
         */
        private boolean checkMsgSignature(String signature, String timestamp, String nonce, String encrypt) {
            try {
                String[] arr = new String[]{encrypt, timestamp, nonce, TOKEN};
                Arrays.sort(arr);
    
                StringBuilder sb = new StringBuilder();
                for (String str : arr) {
                    sb.append(str);
                }
    
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                byte[] digest = md.digest(sb.toString().getBytes());
                StringBuilder hexStr = new StringBuilder();
                for (byte b : digest) {
                    String shaHex = Integer.toHexString(b & 0xFF);
                    if (shaHex.length() < 2) {
                        hexStr.append(0);
                    }
                    hexStr.append(shaHex);
                }
    
                return hexStr.toString().equals(signature);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 解密消息体中的 Encrypt 内容
         */
        private String decryptMessage(String encrypt) {
            try {
                // 1. Base64 解密 Encrypt 字段
                byte[] encryptedBytes = Base64.getDecoder().decode(encrypt);
    
                // 2. 获取 AESKey
                byte[] aesKeyBytes = Base64.getDecoder().decode(ENCODING_AES_KEY + "=");
                SecretKeySpec secretKey = new SecretKeySpec(aesKeyBytes, "AES");
                IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKeyBytes, 0, 16)); // 使用前16字节作为 IV
    
                // 3. AES 解密
                Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
                cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
                byte[] decrypted = cipher.doFinal(encryptedBytes);
    
                // 4.去除补位字符
                decrypted = PKCS7Encoder.decode(decrypted);
    
                // 5. 拆解结构 random(16B) + msg_len(4B) + msg + appid
                ByteBuffer byteBuffer = ByteBuffer.wrap(decrypted);
    
                // 读取 random
                byte[] randomBytes = new byte[16];
                byteBuffer.get(randomBytes);
                String randomStr = new String(randomBytes, StandardCharsets.UTF_8);
    
                // 读取 msg_len(4 字节,网络字节序,大端)
                int msgLen = byteBuffer.getInt();
    
                // 读取 msg
                byte[] msgBytes = new byte[msgLen];
                byteBuffer.get(msgBytes);
                String msg = new String(msgBytes, StandardCharsets.UTF_8);
    
                // 读取 appid
                byte[] appIdBytes = new byte[byteBuffer.remaining()];
                byteBuffer.get(appIdBytes);
                String appId = new String(appIdBytes, StandardCharsets.UTF_8);
    
                // 5. 将解密后的数据以 JSON 格式返回
                JSONObject jsonResponse = new JSONObject();
                jsonResponse.put("random", randomStr);
                jsonResponse.put("msg_len", msgLen);
                jsonResponse.put("msg", msg);
                jsonResponse.put("appid", appId);
                return jsonResponse.toString();  // 返回 JSON 格式字符串
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
    
        /**
         * 构造回包并加密
         */
        private String createResponse(String message) {
            try {
                // 1. 构造 FullStr
                String randomStr = generateRandomString(16);  // 随机生成16字节
                byte[] msgBytes = message.getBytes("UTF-8");
    
                // 2. 构造消息头:random(16B) + msg_len(4B) + msg
                byte[] msgLenBytes = intToByteArray(msgBytes.length);  // 长度占4字节
                byte[] fullMessage = new byte[randomStr.length() + 4 + msgBytes.length];
    
                // 拼接消息
                System.arraycopy(randomStr.getBytes("UTF-8"), 0, fullMessage, 0, randomStr.length());
                System.arraycopy(msgLenBytes, 0, fullMessage, randomStr.length(), msgLenBytes.length);
                System.arraycopy(msgBytes, 0, fullMessage, randomStr.length() + 4, msgBytes.length);
    
                // 3. 用 AES 加密消息
                byte[] encryptedMessage = encryptWithAES(fullMessage);
    
                // 4. Base64 编码加密结果
                String encrypt = Base64.getEncoder().encodeToString(encryptedMessage);
    
                // 5. 生成签名
                String msgSignature = generateMsgSignature(encrypt);
    
                // 6. 构造回包
                long timeStamp = System.currentTimeMillis() / 1000;  // 当前时间戳,单位秒
                int nonce = new Random().nextInt(Integer.MAX_VALUE);  // 随机生成一个 nonce
    
                // 7. 构造回包
                return "{\"Encrypt\": \"" + encrypt + "\", \"MsgSignature\": \"" + msgSignature + "\", \"TimeStamp\": " + timeStamp + ", \"Nonce\": " + nonce + "}";
            } catch (Exception e) {
                e.printStackTrace();
                return "{\"error\":\"Failed to create response\"}";
            }
        }
    
        /**
         * AES 加密
         */
        private byte[] encryptWithAES(byte[] data) throws Exception {
            byte[] aesKeyBytes = Base64.getDecoder().decode(ENCODING_AES_KEY + "=");
    
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec secretKey = new SecretKeySpec(aesKeyBytes, "AES");
            IvParameterSpec iv = new IvParameterSpec(aesKeyBytes, 0, 16); // 使用前16字节作为 IV
    
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); // 使用空的 16 字节偏移量
    
            return cipher.doFinal(data);
        }
    
        /**
         * 生成消息签名
         */
        private String generateMsgSignature(String encrypt) throws Exception {
            String[] arr = new String[]{"1713424427", "415670741", TOKEN, encrypt};
            Arrays.sort(arr);
    
            StringBuilder sb = new StringBuilder();
            for (String str : arr) {
                sb.append(str);
            }
    
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(sb.toString().getBytes());
    
            StringBuilder hexStr = new StringBuilder();
            for (byte b : digest) {
                String shaHex = Integer.toHexString(b & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
    
            return hexStr.toString();
        }
    
        // 将整数转化为网络字节序的4字节
        private byte[] intToByteArray(int num) {
            return new byte[]{
                (byte) (num >>> 24),
                (byte) (num >>> 16),
                (byte) (num >>> 8),
                (byte) num
            };
        }
    
        /**
         * 生成固定长度的随机字符串
         */
        private String generateRandomString(int length) {
            StringBuilder sb = new StringBuilder();
            String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            Random random = new Random();
            for (int i = 0; i < length; i++) {
                sb.append(chars.charAt(random.nextInt(chars.length())));
            }
            return sb.toString();
        }
    
    }
    
    本文著作权归作者 [ admin ] 享有,未经作者书面授权,禁止转载,封面图片来源于 [ 互联网 ] ,本文仅供个人学习、研究和欣赏使用。如有异议,请联系博主及时处理。
    取消回复

    发表留言
    回复

    首页邻居关于归档
    Copyright©2020-2026  All Rights Reserved.  Load:0.018 s
    京ICP备18019712号
    Theme by OneBlog V3.6.5
    夜间模式

    开源不易,请尊重作者版权,保留基本的版权信息。