|  |  | 
 |  |  | 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; | 
 |  |  | 
 |  |  |     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; | 
 |  |  |  | 
 |  |  |     // 平台证书公钥 | 
 |  |  | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 获取商户证书私钥对象 | 
 |  |  |      * @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-----", "") | 
 |  |  | 
 |  |  |     /** | 
 |  |  |      * 签名 | 
 |  |  |      * @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()); | 
 |  |  |     } | 
 |  |  | 
 |  |  |      * @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 + "\"," | 
 |  |  | 
 |  |  |     /** | 
 |  |  |      * 重新下载证书 | 
 |  |  |      */ | 
 |  |  |     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); | 
 |  |  | 
 |  |  |      * @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) { | 
 |  |  | 
 |  |  |      * @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); | 
 |  |  | 
 |  |  |         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); |