From 4742874ad840d7e1e3ac79dc288b38e9a642319d Mon Sep 17 00:00:00 2001 From: 无关风月 <443237572@qq.com> Date: 星期一, 02 六月 2025 19:11:00 +0800 Subject: [PATCH] bug修改 --- cloud-server-activity/src/main/java/com/dsh/activity/util/wx/WXPaySignatureCertificateUtil.java | 595 +++++++++++++++++++++++++++++----------------------------- 1 files changed, 297 insertions(+), 298 deletions(-) diff --git a/cloud-server-activity/src/main/java/com/dsh/activity/util/wx/WXPaySignatureCertificateUtil.java b/cloud-server-activity/src/main/java/com/dsh/activity/util/wx/WXPaySignatureCertificateUtil.java index ccc2e53..02a18af 100644 --- a/cloud-server-activity/src/main/java/com/dsh/activity/util/wx/WXPaySignatureCertificateUtil.java +++ b/cloud-server-activity/src/main/java/com/dsh/activity/util/wx/WXPaySignatureCertificateUtil.java @@ -1,298 +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); - } - } -} \ No newline at end of file +//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); +// } +// } +//} \ No newline at end of file -- Gitblit v1.7.1