无关风月
4 天以前 4742874ad840d7e1e3ac79dc288b38e9a642319d
cloud-server-activity/src/main/java/com/dsh/activity/util/wx/WXPaySignatureCertificateUtil.java
@@ -1,297 +1,297 @@
package com.dsh.activity.util.wx;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.SneakyThrows;
import org.apache.http.impl.client.CloseableHttpClient;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * 微信支付V3 API 签名验证工具类
 */
public class WXPaySignatureCertificateUtil {
    // 保存微信平台证书
    private static final ConcurrentHashMap<String, AutoUpdateCertificatesVerifier> verifierMap = new ConcurrentHashMap<>();
    // 缓存公钥,避免频繁IO操作
    private static PublicKey cachedPublicKey = null;
    // 缓存私钥,避免频繁IO操作
    private static PrivateKey cachedPrivateKey = null;
    /**
     * 获取HTTP客户端,用于微信支付API请求
     */
    public static CloseableHttpClient getWechatPayClient() throws IOException {
        PrivateKey merchantPrivateKey = getPrivateKey();
        // 构建支付客户端
        return WechatPayHttpClientBuilder.create()
                .withMerchant(WxV3PayConfig.Mch_ID, WxV3PayConfig.mchSerialNo, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(getVerifier()))
                .build();
    }
    /**
     * 获取自动更新的证书验证器
     */
    public static AutoUpdateCertificatesVerifier getVerifier() {
        String mchSerialNo = WxV3PayConfig.mchSerialNo;
        AutoUpdateCertificatesVerifier verifier = verifierMap.get(mchSerialNo);
        if (verifier == null) {
            synchronized (WXPaySignatureCertificateUtil.class) {
                verifier = verifierMap.get(mchSerialNo);
                if (verifier == null) {
                    try {
                        PrivateKey privateKey = getPrivateKey();
                        PrivateKeySigner signer = new PrivateKeySigner(mchSerialNo, privateKey);
                        WechatPay2Credentials credentials = new WechatPay2Credentials(WxV3PayConfig.Mch_ID, signer);
                        verifier = new AutoUpdateCertificatesVerifier(
                                credentials, WxV3PayConfig.apiV3Key.getBytes(StandardCharsets.UTF_8));
                        verifierMap.put(mchSerialNo, verifier);
                    } catch (Exception e) {
                        throw new RuntimeException("初始化证书验证器失败", e);
                    }
                }
            }
        }
        return verifier;
    }
    /**
     * 使用商户私钥对数据进行签名
     *
     * @param message 待签名数据
     * @return Base64编码的签名结果
     */
    public static String sign(String message) {
        try {
            PrivateKey privateKey = getPrivateKey();
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(privateKey);
            signature.update(message.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(signature.sign());
        } catch (Exception e) {
            throw new RuntimeException("签名失败", e);
        }
    }
    /**
     * 使用微信支付平台公钥验证签名
     *
     * @param message 原始消息
     * @param signature Base64编码的签名
     * @return 验证结果
     */
    public static boolean verifySign(String message, String signature) {
        try {
            PublicKey publicKey = getWechatPublicKey();
            Signature sig = Signature.getInstance("SHA256withRSA");
            sig.initVerify(publicKey);
            sig.update(message.getBytes(StandardCharsets.UTF_8));
            return sig.verify(Base64.getDecoder().decode(signature));
        } catch (Exception e) {
            throw new RuntimeException("验签失败", e);
        }
    }
    /**
     * 验证微信支付通知消息的签名
     *
     * @param request HTTP请求
     * @param body 请求体内容
     * @return 验证结果
     */
    public static boolean verifyNotify(HttpServletRequest request, String body) {
        try {
            // 获取必要的HTTP头信息
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");
            // 拼接验签字符串
            String message = Stream.of(timestamp, nonce, body)
                    .collect(Collectors.joining("\n", "", "\n"));
            // 使用自动更新的证书验证器进行验证
            return getVerifier().verify(serialNo, message.getBytes(StandardCharsets.UTF_8), signature);
        } catch (Exception e) {
            throw new RuntimeException("验证微信支付通知签名失败", e);
        }
    }
    /**
     * APP支付签名
     */
    public static String appPaySign(String timestamp, String nonceStr, String prepayId) {
        String message = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        return sign(message);
    }
    /**
     * JSAPI支付签名
     */
    public static String jsApiPaySign(String timestamp, String nonceStr, String prepayId) {
        String message = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, "prepay_id="+prepayId)
                .collect(Collectors.joining("\n", "", "\n"));
        return sign(message);
    }
    /**
     * 构建App支付参数
     */
    public static Map<String, String> buildAppPayParams(String prepayId) {
        try {
            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
            String nonceStr = generateNonceStr();
            String sign = appPaySign(timestamp, nonceStr, prepayId);
            Map<String, String> params = new HashMap<>();
            params.put("appid", WxV3PayConfig.APP_ID);
            params.put("partnerid", WxV3PayConfig.Mch_ID);
            params.put("prepayid", prepayId);
            params.put("package", "Sign=WXPay");
            params.put("noncestr", nonceStr);
            params.put("timestamp", timestamp);
            params.put("sign", sign);
            return params;
        } catch (Exception e) {
            throw new RuntimeException("构建App支付参数失败", e);
        }
    }
    /**
     * 构建JSAPI支付参数
     */
    public static Map<String, String> buildJsApiPayParams(String prepayId) {
        try {
            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
            String nonceStr = generateNonceStr();
            String sign = jsApiPaySign(timestamp, nonceStr, prepayId);
            Map<String, String> params = new HashMap<>();
            params.put("appId", WxV3PayConfig.APP_ID);
            params.put("timeStamp", timestamp);
            params.put("nonceStr", nonceStr);
            params.put("package", "prepay_id=" + prepayId);
            params.put("signType", "RSA");
            params.put("paySign", sign);
            return params;
        } catch (Exception e) {
            throw new RuntimeException("构建JSAPI支付参数失败", e);
        }
    }
    /**
     * 生成随机字符串
     */
    private static String generateNonceStr() {
        return java.util.UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
    }
    /**
     * 获取商户私钥
     */
    public static PrivateKey getPrivateKey() {
        if (cachedPrivateKey != null) {
            return cachedPrivateKey;
        }
        try {
            String filePath = "D:\\玩湃v3参数\\apiclient_key.pem";
            String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");
            KeyFactory kf = KeyFactory.getInstance("RSA");
            cachedPrivateKey = kf.generatePrivate(
                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
            return cachedPrivateKey;
        } catch (IOException e) {
            throw new RuntimeException("读取私钥文件失败", e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式", e);
        }
    }
    /**
     * 获取微信支付平台公钥
     */
    public static PublicKey getWechatPublicKey() {
        if (cachedPublicKey != null) {
            return cachedPublicKey;
        }
        try {
            // 使用验证器获取最新的证书
            X509Certificate certificate = getVerifier().getValidCertificate();
            cachedPublicKey = certificate.getPublicKey();
            return cachedPublicKey;
        } catch (Exception e) {
            throw new RuntimeException("获取微信平台公钥失败", e);
        }
    }
    /**
     * 从PEM格式文件加载公钥
     */
    public static PublicKey loadPublicKeyFromFile(String filePath) {
        try {
            String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
            String publicKeyPEM = content
                    .replace("-----BEGIN PUBLIC KEY-----", "")
                    .replace("-----END PUBLIC KEY-----", "")
                    .replaceAll("\\s+", "");
            byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
        } catch (Exception e) {
            throw new RuntimeException("加载公钥文件失败", e);
        }
    }
    /**
     * 从证书文件加载公钥
     */
    public static PublicKey loadPublicKeyFromCert(String filePath) {
        try (FileInputStream inputStream = new FileInputStream(filePath)) {
            CertificateFactory factory = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) factory.generateCertificate(inputStream);
            return cert.getPublicKey();
        } catch (Exception e) {
            throw new RuntimeException("加载证书文件失败", e);
        }
    }
}
//package com.dsh.activity.util.wx;
//
//import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
//import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
//import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
//import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
//import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
//import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
//import lombok.SneakyThrows;
//import org.apache.http.impl.client.CloseableHttpClient;
//
//import javax.servlet.http.HttpServletRequest;
//import java.io.*;
//import java.nio.charset.StandardCharsets;
//import java.nio.file.Files;
//import java.nio.file.Paths;
//import java.security.*;
//import java.security.cert.Certificate;
//import java.security.cert.CertificateException;
//import java.security.cert.CertificateFactory;
//import java.security.cert.X509Certificate;
//import java.security.spec.InvalidKeySpecException;
//import java.security.spec.PKCS8EncodedKeySpec;
//import java.security.spec.X509EncodedKeySpec;
//import java.util.Base64;
//import java.util.HashMap;
//import java.util.Map;
//import java.util.concurrent.ConcurrentHashMap;
//import java.util.stream.Collectors;
//import java.util.stream.Stream;
//
///**
// * 微信支付V3 API 签名验证工具类
// */
//public class WXPaySignatureCertificateUtil {
//
//    // 保存微信平台证书
//    private static final ConcurrentHashMap<String, AutoUpdateCertificatesVerifier> verifierMap = new ConcurrentHashMap<>();
//    // 缓存公钥,避免频繁IO操作
//    private static PublicKey cachedPublicKey = null;
//    // 缓存私钥,避免频繁IO操作
//    private static PrivateKey cachedPrivateKey = null;
//
//    /**
//     * 获取HTTP客户端,用于微信支付API请求
//     */
//    public static CloseableHttpClient getWechatPayClient() throws IOException {
//        PrivateKey merchantPrivateKey = getPrivateKey();
//        // 构建支付客户端
//        return WechatPayHttpClientBuilder.create()
//                .withMerchant(WxV3PayConfig.Mch_ID, WxV3PayConfig.mchSerialNo, merchantPrivateKey)
//                .withValidator(new WechatPay2Validator(getVerifier()))
//                .build();
//    }
//
//    /**
//     * 获取自动更新的证书验证器
//     */
//    public static AutoUpdateCertificatesVerifier getVerifier() {
//        String mchSerialNo = WxV3PayConfig.mchSerialNo;
//        AutoUpdateCertificatesVerifier verifier = verifierMap.get(mchSerialNo);
//
//        if (verifier == null) {
//            synchronized (WXPaySignatureCertificateUtil.class) {
//                verifier = verifierMap.get(mchSerialNo);
//                if (verifier == null) {
//                    try {
//                        PrivateKey privateKey = getPrivateKey();
//                        PrivateKeySigner signer = new PrivateKeySigner(mchSerialNo, privateKey);
//                        WechatPay2Credentials credentials = new WechatPay2Credentials(WxV3PayConfig.Mch_ID, signer);
//                        verifier = new AutoUpdateCertificatesVerifier(
//                                credentials, WxV3PayConfig.apiV3Key.getBytes(StandardCharsets.UTF_8));
//                        verifierMap.put(mchSerialNo, verifier);
//                    } catch (Exception e) {
//                        throw new RuntimeException("初始化证书验证器失败", e);
//                    }
//                }
//            }
//        }
//
//        return verifier;
//    }
//
//    /**
//     * 使用商户私钥对数据进行签名
//     *
//     * @param message 待签名数据
//     * @return Base64编码的签名结果
//     */
//    public static String sign(String message) {
//        try {
//            PrivateKey privateKey = getPrivateKey();
//            Signature signature = Signature.getInstance("SHA256withRSA");
//            signature.initSign(privateKey);
//            signature.update(message.getBytes(StandardCharsets.UTF_8));
//            return Base64.getEncoder().encodeToString(signature.sign());
//        } catch (Exception e) {
//            throw new RuntimeException("签名失败", e);
//        }
//    }
//
//    /**
//     * 使用微信支付平台公钥验证签名
//     *
//     * @param message 原始消息
//     * @param signature Base64编码的签名
//     * @return 验证结果
//     */
//    public static boolean verifySign(String message, String signature) {
//        try {
//            PublicKey publicKey = getWechatPublicKey();
//            Signature sig = Signature.getInstance("SHA256withRSA");
//            sig.initVerify(publicKey);
//            sig.update(message.getBytes(StandardCharsets.UTF_8));
//            return sig.verify(Base64.getDecoder().decode(signature));
//        } catch (Exception e) {
//            throw new RuntimeException("验签失败", e);
//        }
//    }
//
//    /**
//     * 验证微信支付通知消息的签名
//     *
//     * @param request HTTP请求
//     * @param body 请求体内容
//     * @return 验证结果
//     */
//    public static boolean verifyNotify(HttpServletRequest request, String body) {
//        try {
//            // 获取必要的HTTP头信息
//            String timestamp = request.getHeader("Wechatpay-Timestamp");
//            String nonce = request.getHeader("Wechatpay-Nonce");
//            String serialNo = request.getHeader("Wechatpay-Serial");
//            String signature = request.getHeader("Wechatpay-Signature");
//
//            // 拼接验签字符串
//            String message = Stream.of(timestamp, nonce, body)
//                    .collect(Collectors.joining("\n", "", "\n"));
//
//            // 使用自动更新的证书验证器进行验证
//            return getVerifier().verify(serialNo, message.getBytes(StandardCharsets.UTF_8), signature);
//        } catch (Exception e) {
//            throw new RuntimeException("验证微信支付通知签名失败", e);
//        }
//    }
//
//    /**
//     * APP支付签名
//     */
//    public static String appPaySign(String timestamp, String nonceStr, String prepayId) {
//        String message = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, prepayId)
//                .collect(Collectors.joining("\n", "", "\n"));
//        return sign(message);
//    }
//
//    /**
//     * JSAPI支付签名
//     */
//    public static String jsApiPaySign(String timestamp, String nonceStr, String prepayId) {
//        String message = Stream.of(WxV3PayConfig.APP_ID, timestamp, nonceStr, "prepay_id="+prepayId)
//                .collect(Collectors.joining("\n", "", "\n"));
//        return sign(message);
//    }
//
//    /**
//     * 构建App支付参数
//     */
//    public static Map<String, String> buildAppPayParams(String prepayId) {
//        try {
//            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
//            String nonceStr = generateNonceStr();
//            String sign = appPaySign(timestamp, nonceStr, prepayId);
//            Map<String, String> params = new HashMap<>();
//            params.put("appid", WxV3PayConfig.APP_ID);
//            params.put("partnerid", WxV3PayConfig.Mch_ID);
//            params.put("prepayid", prepayId);
//            params.put("package", "Sign=WXPay");
//            params.put("noncestr", nonceStr);
//            params.put("timestamp", timestamp);
//            params.put("sign", sign);
//
//            return params;
//        } catch (Exception e) {
//            throw new RuntimeException("构建App支付参数失败", e);
//        }
//    }
//
//    /**
//     * 构建JSAPI支付参数
//     */
//    public static Map<String, String> buildJsApiPayParams(String prepayId) {
//        try {
//            String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
//            String nonceStr = generateNonceStr();
//            String sign = jsApiPaySign(timestamp, nonceStr, prepayId);
//
//            Map<String, String> params = new HashMap<>();
//            params.put("appId", WxV3PayConfig.APP_ID);
//            params.put("timeStamp", timestamp);
//            params.put("nonceStr", nonceStr);
//            params.put("package", "prepay_id=" + prepayId);
//            params.put("signType", "RSA");
//            params.put("paySign", sign);
//
//            return params;
//        } catch (Exception e) {
//            throw new RuntimeException("构建JSAPI支付参数失败", e);
//        }
//    }
//
//    /**
//     * 生成随机字符串
//     */
//    private static String generateNonceStr() {
//        return java.util.UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
//    }
//
//    /**
//     * 获取商户私钥
//     */
//    public static PrivateKey getPrivateKey() {
//        if (cachedPrivateKey != null) {
//            return cachedPrivateKey;
//        }
//
//        try {
//            String filePath = "D:\\玩湃v3参数\\apiclient_key.pem";
//            String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
//
//            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
//                    .replace("-----END PRIVATE KEY-----", "")
//                    .replaceAll("\\s+", "");
//
//            KeyFactory kf = KeyFactory.getInstance("RSA");
//            cachedPrivateKey = kf.generatePrivate(
//                    new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
//            return cachedPrivateKey;
//        } catch (IOException e) {
//            throw new RuntimeException("读取私钥文件失败", e);
//        } catch (NoSuchAlgorithmException e) {
//            throw new RuntimeException("当前Java环境不支持RSA", e);
//        } catch (InvalidKeySpecException e) {
//            throw new RuntimeException("无效的密钥格式", e);
//        }
//    }
//
//    /**
//     * 获取微信支付平台公钥
//     */
//    public static PublicKey getWechatPublicKey() {
//        if (cachedPublicKey != null) {
//            return cachedPublicKey;
//        }
//
//        try {
//            // 使用验证器获取最新的证书
//            X509Certificate certificate = getVerifier().getValidCertificate();
//            cachedPublicKey = certificate.getPublicKey();
//            return cachedPublicKey;
//        } catch (Exception e) {
//            throw new RuntimeException("获取微信平台公钥失败", e);
//        }
//    }
//
//    /**
//     * 从PEM格式文件加载公钥
//     */
//    public static PublicKey loadPublicKeyFromFile(String filePath) {
//        try {
//            String content = new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8);
//
//            String publicKeyPEM = content
//                    .replace("-----BEGIN PUBLIC KEY-----", "")
//                    .replace("-----END PUBLIC KEY-----", "")
//                    .replaceAll("\\s+", "");
//
//            byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
//            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//            return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
//        } catch (Exception e) {
//            throw new RuntimeException("加载公钥文件失败", e);
//        }
//    }
//
//    /**
//     * 从证书文件加载公钥
//     */
//    public static PublicKey loadPublicKeyFromCert(String filePath) {
//        try (FileInputStream inputStream = new FileInputStream(filePath)) {
//            CertificateFactory factory = CertificateFactory.getInstance("X.509");
//            X509Certificate cert = (X509Certificate) factory.generateCertificate(inputStream);
//            return cert.getPublicKey();
//        } catch (Exception e) {
//            throw new RuntimeException("加载证书文件失败", e);
//        }
//    }
//}