zhubaomin
2025-04-03 c6beb89b7170115eada78526f87406381c931229
pipIrr-platform/pipIrr-web/pipIrr-web-wechat/src/main/java/com/dy/pipIrrWechat/util/PayHelper.java
@@ -21,8 +21,6 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
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;
@@ -51,7 +49,6 @@
    private String resetUserSessionKeyUrl = PayInfo.resetUserSessionKeyUrl;
    private String notifyUrl = PayInfo.notifyUrl;
    private String schema = PayInfo.schema;
    private String privateCertFileName = PayInfo.privateCertFileName;
    private String refundUrl = PayInfo.refundUrl;
    // 平台证书公钥
@@ -73,12 +70,25 @@
    /**
     * 获取商户证书私钥对象
     * @param filename 私钥文件路径
     * @param certFileBs 私钥文件内容
     * @return 私钥对象
     * @throws IOException
     */
    public PrivateKey getPrivateKey(String filename) throws IOException {
        String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s+", "");
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("当前Java环境不支持RSA", e);
        } catch (InvalidKeySpecException e) {
            throw new RuntimeException("无效的密钥格式");
        }
    }*/
    public PrivateKey getPrivateKey(byte[] certFileBs) throws IOException {
        String content = new String(certFileBs, "utf-8");
        try {
            String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
@@ -208,16 +218,21 @@
    /**
     * 签名
     * @param message 被签名信息
     * @param certFileName 私钥证书文件路径
     * @param certBs 私钥证书文件内容
     * @return signature签名值,签名信息中的一项,参与生成签名信息
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     * @throws IOException
     */
    public String sign(byte[] message, String certFileName) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPrivateKey(certFileName));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }*/
    public String sign(byte[] message, byte[] certBs) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, IOException, Exception {
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(getPrivateKey(certBs));
        sign.update(message);
        return Base64.getEncoder().encodeToString(sign.sign());
    }
@@ -230,10 +245,19 @@
     * @return 签名信息,HTTP头中的签名信息
     * HTTP头:Authorization: 认证类型 签名信息
     * 认证类型,WECHATPAY2-SHA256-RSA2048
     */
    public String getToken(String method, String url, String body, String nonceStr, Long timestamp, String certFileName) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, NoSuchPaddingException {
        String message = buildMessage_order(method, url, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"), certFileName);
        return "mchid=\"" + PayInfo.mchid + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timestamp + "\","
                + "serial_no=\"" + PayInfo.serial_no + "\","
                + "signature=\"" + signature + "\"";
    }*/
    public String getToken(String method, String url, String body, String nonceStr, Long timestamp, byte[] certFileBs) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException, Exception {
        String message = buildMessage_order(method, url, timestamp, nonceStr, body);
        String signature = sign(message.getBytes("utf-8"), certFileBs);
        return "mchid=\"" + PayInfo.mchid + "\","
                + "nonce_str=\"" + nonceStr + "\","
@@ -259,13 +283,13 @@
    /**
     * 重新下载证书
     */
    public void refreshCertificate() throws GeneralSecurityException, IOException {
    public void refreshCertificate(byte[] certFileBs) throws GeneralSecurityException, IOException , Exception {
        String method = "GET";
        String httpUrl = "/v3/certificates";
        String nonceStr = generateRandomString();
        Long timestamp = System.currentTimeMillis() / 1000;
        String header = PayInfo.schema + " " + getToken(method, httpUrl, "", nonceStr, timestamp, PayInfo.privateCertFileName);
        String header = PayInfo.schema + " " + getToken(method, httpUrl, "", nonceStr, timestamp, certFileBs);
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", header);
@@ -330,10 +354,10 @@
     * @throws InvalidKeyException
     * @throws SignatureException
     */
    public Boolean responseSignVerify(String wechatpaySerial, String signatureStr, String wechatpaySignature) throws GeneralSecurityException, IOException {
    public Boolean responseSignVerify(String wechatpaySerial, String signatureStr, String wechatpaySignature, byte[] certFileBs) throws Exception {
        if(CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
            CERTIFICATE_MAP.clear();
            refreshCertificate();
            refreshCertificate(certFileBs);
        }
        Certificate certificate = (Certificate)CERTIFICATE_MAP.get(wechatpaySerial);
        if(certificate == null) {
@@ -457,13 +481,13 @@
     * @throws SignatureException
     * @throws InvalidKeyException
     */
    public BaseResponse<Boolean> refunds(Refund po) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException {
    public BaseResponse<Boolean> refunds(Refund po, byte[] certFileBs) throws SignatureException, InvalidKeyException, Exception{
        String tradeNo = po.getTradeNo();
        String refundNo = po.getRefundNo();
        Integer refund = po.getRefund();
        // 生成body
        Integer total = virtualCardSv.getRechargeAmountByOrderNumber(tradeNo);
        Double total = virtualCardSv.getRechargeAmountByOrderNumber(tradeNo);
        RefundRequest.Amount amount = new RefundRequest.Amount();
        amount.setRefund(refund);
        amount.setTotal(total);
@@ -483,7 +507,7 @@
        String httpUrl = "/v3/refund/domestic/refunds";
        String body = JSONObject.toJSONString(refundRequest);
        String header = schema + " " + getToken(method, httpUrl, body, nonceStr, timestamp, privateCertFileName);
        String header = schema + " " + getToken(method, httpUrl, body, nonceStr, timestamp, certFileBs);
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", header);