微信请求加密
This commit is contained in:
@@ -18,7 +18,7 @@ public class WechatConfig {
|
||||
* @param dto 微信支付配置
|
||||
* @return 微信支付配置
|
||||
*/
|
||||
public static Config getConfig(WechatPayConfigDto dto) {
|
||||
public static Config getRsaConfig(WechatPayConfigDto dto) {
|
||||
return new RSAPublicKeyConfig.Builder()
|
||||
.merchantId(dto.getMerchantId())
|
||||
.privateKey(dto.getPrivateKey())
|
||||
@@ -41,7 +41,7 @@ public class WechatConfig {
|
||||
* @return 文件上传服务
|
||||
*/
|
||||
public static FileUploadService getFileUploadService(WechatPayConfigDto dto) {
|
||||
return getFileUploadService(getConfig(dto));
|
||||
return getFileUploadService(getRsaConfig(dto));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,45 @@
|
||||
package com.czg.wechat;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* 微信支付加解密
|
||||
* @author yjjie
|
||||
* @date 2025/12/26 10:58
|
||||
*/
|
||||
@Slf4j
|
||||
public class WechatEncrypt {
|
||||
|
||||
public static String rsaEncryptOaep(String message, PublicKey publicKey) {
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||
byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] cipherData = cipher.doFinal(data);
|
||||
return Base64.getEncoder().encodeToString(cipherData);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
log.error("当前Java环境不支持RSA v1.5/OAEP");
|
||||
} catch (InvalidKeyException e) {
|
||||
log.error("无效的证书");
|
||||
} catch (IllegalBlockSizeException | BadPaddingException e) {
|
||||
log.error("加密原串的长度不能超过214字节");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static String getFileBytesSha256(byte[] input) throws NoSuchAlgorithmException {
|
||||
return bytesToHex(calculateSha256(input));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,15 @@ package com.czg.wechat;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.czg.wechat.dto.config.WechatPayConfigDto;
|
||||
import com.czg.wechat.dto.req.entry.WechatEntryReqDto;
|
||||
import com.czg.wechat.dto.req.entry.*;
|
||||
import com.czg.wechat.dto.req.entry.business.WechatEntryBusinessReqDto;
|
||||
import com.czg.wechat.dto.req.entry.business.WechatEntryIdentityReqDto;
|
||||
import com.czg.wechat.dto.req.entry.business.WechatEntryLicenseReqDto;
|
||||
import com.czg.wechat.dto.req.entry.business.sales.WechatEntrySalesInfoReqDto;
|
||||
import com.czg.wechat.dto.req.entry.business.sales.WechatEntryStoreInfoReqDto;
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.cipher.PrivacyEncryptor;
|
||||
import com.wechat.pay.java.core.cipher.Signer;
|
||||
import com.wechat.pay.java.service.file.FileUploadService;
|
||||
import com.wechat.pay.java.service.file.model.FileUploadResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -12,6 +20,8 @@ import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 微信支付进件 管理
|
||||
@@ -22,6 +32,21 @@ import java.net.http.HttpResponse;
|
||||
@Slf4j
|
||||
public class WechatEntryManager {
|
||||
|
||||
public static void entryMerchant(WechatPayConfigDto configDto, WechatEntryReqDto reqDto) {
|
||||
String params = JSONObject.toJSONString(reqDto, JSONWriter.Feature.IgnoreEmpty);
|
||||
|
||||
// String string = WechatReqUtils.encryptReqParam(configDto, "POST", "/v3/applyment4sub/applyment/", params);
|
||||
|
||||
WechatReqUtils.postReq(configDto, "POST", "/v3/applyment4sub/applyment/", params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传图片
|
||||
*
|
||||
* @param configDto 配置
|
||||
* @param url 图片URL
|
||||
* @return 图片ID
|
||||
*/
|
||||
public static String uploadImage(WechatPayConfigDto configDto, String url) {
|
||||
// 校验入参
|
||||
if (configDto == null || url == null || url.trim().isEmpty()) {
|
||||
@@ -156,7 +181,78 @@ public class WechatEntryManager {
|
||||
// String string = uploadImage(dto, "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png");
|
||||
// log.info("图片上传成功:{}", string);
|
||||
|
||||
WechatEntryReqDto reqDto = new WechatEntryReqDto();
|
||||
System.out.println(JSONObject.toJSONString(reqDto, JSONWriter.Feature.IgnoreEmpty));
|
||||
Config config = WechatConfig.getRsaConfig(dto);
|
||||
PrivacyEncryptor encryptor = config.createEncryptor();
|
||||
|
||||
WechatEntryReqDto reqDto = new WechatEntryReqDto()
|
||||
.setBusinessCode("MER_20231025110010000010000000000001");
|
||||
|
||||
WechatEntryContactReqDto contactInfo = new WechatEntryContactReqDto()
|
||||
.setContactType("LEGAL")
|
||||
.setContactName(encryptor.encrypt("张三"))
|
||||
.setContactIdType("IDCARD")
|
||||
.setContactIdNumber(encryptor.encrypt("110101199001011234"))
|
||||
.setContactIdDocCopy("https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png")
|
||||
.setContactIdDocCopyBack("https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png")
|
||||
.setContactPeriodBegin("2023-10-25")
|
||||
.setContactPeriodEnd("2024-10-25")
|
||||
.setMobilePhone(encryptor.encrypt("13888888888"))
|
||||
.setContactEmail(encryptor.encrypt("123456@qq.com"));
|
||||
|
||||
reqDto.setContactInfo(contactInfo);
|
||||
|
||||
WechatEntrySubjectReqDto subjectInfo = new WechatEntrySubjectReqDto()
|
||||
.setSubjectType("SUBJECT_TYPE_INDIVIDUAL");
|
||||
|
||||
WechatEntryLicenseReqDto licenseInfo = new WechatEntryLicenseReqDto()
|
||||
.setLicenseCopy("https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png")
|
||||
.setLicenseNumber("110101199001011234")
|
||||
.setMerchantName("张三商行")
|
||||
.setLegalPerson(encryptor.encrypt("张三"))
|
||||
.setLicenseAddress("北京")
|
||||
.setPeriodBegin("2023-10-25")
|
||||
.setPeriodEnd("2024-10-25");
|
||||
subjectInfo.setBusinessLicenseInfo(licenseInfo);
|
||||
|
||||
WechatEntryIdentityReqDto identityInfo = new WechatEntryIdentityReqDto()
|
||||
.setIdHolderType("LEGAL");
|
||||
subjectInfo.setIdentityInfo(identityInfo);
|
||||
|
||||
reqDto.setSubjectInfo(subjectInfo);
|
||||
|
||||
WechatEntryBusinessReqDto businessInfo = new WechatEntryBusinessReqDto()
|
||||
.setMerchantShortname("张三商行")
|
||||
.setServicePhone("13888888888");
|
||||
WechatEntrySalesInfoReqDto salesInfo = new WechatEntrySalesInfoReqDto()
|
||||
.setSalesScenesType(List.of("SALES_SCENES_STORE"));
|
||||
WechatEntryStoreInfoReqDto storeInfo = new WechatEntryStoreInfoReqDto()
|
||||
.setBizStoreName("张三商行")
|
||||
.setBizAddressCode("110101")
|
||||
.setBizStoreAddress("北京")
|
||||
.setStoreEntrancePic(List.of("https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png"))
|
||||
.setIndoorPic(List.of("https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png"));
|
||||
salesInfo.setBizStoreInfo(storeInfo);
|
||||
businessInfo.setSalesInfo(salesInfo);
|
||||
|
||||
reqDto.setBusinessInfo(businessInfo);
|
||||
|
||||
WechatEntrySettleReqDto settleInfo = new WechatEntrySettleReqDto()
|
||||
.setSettlementId("719")
|
||||
.setQualificationType("IDCARD")
|
||||
.setQualifications(List.of("110101199001011234"))
|
||||
.setActivitiesId("20191030111cff5b5e");
|
||||
|
||||
reqDto.setSettlementInfo(settleInfo);
|
||||
|
||||
WechatEntryBankAccountReqDto bankAccountInfo = new WechatEntryBankAccountReqDto()
|
||||
.setBankAccountType("BANK_ACCOUNT_TYPE_CORPORATE")
|
||||
.setAccountBank("ICBC")
|
||||
.setBankName("中国工商银行")
|
||||
.setAccountName(encryptor.encrypt("张三"))
|
||||
.setAccountNumber(encryptor.encrypt("110101199001011234"));
|
||||
|
||||
reqDto.setBankAccountInfo(bankAccountInfo);
|
||||
|
||||
entryMerchant(dto, reqDto);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.czg.wechat;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.czg.wechat.dto.config.WechatPayConfigDto;
|
||||
import com.wechat.pay.java.core.Config;
|
||||
import com.wechat.pay.java.core.RSAPublicKeyConfig;
|
||||
import com.wechat.pay.java.core.cipher.PrivacyEncryptor;
|
||||
import com.wechat.pay.java.core.cipher.Signer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 微信请求工具类
|
||||
*
|
||||
* @author yjjie
|
||||
* @date 2025/12/29 10:02
|
||||
*/
|
||||
@Slf4j
|
||||
public class WechatReqUtils {
|
||||
|
||||
public static String postReq(WechatPayConfigDto configDto, String method, String url, String body) {
|
||||
long timestamp = getTimestamp();
|
||||
String nonce = getNonceStr();
|
||||
|
||||
String signature = encryptReqParam(configDto, method, url, body, timestamp, nonce);
|
||||
|
||||
String authorization = String.format("WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\",timestamp=\"%d\",serial_no=\"%s\"",
|
||||
configDto.getMerchantId(), nonce, signature, timestamp, "4DE9BAC2EA584C3F274F694C9753CA814C4E9BF4");
|
||||
|
||||
log.info("authorization = {}", authorization);
|
||||
|
||||
HttpRequest request = HttpUtil.createPost(configDto.getDomain() + url)
|
||||
.header("Authorization", authorization)
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Wechatpay-Serial", configDto.getPublicKeyId())
|
||||
// .header("Wechatpay-Serial", "4DE9BAC2EA584C3F274F694C9753CA814C4E9BF4")
|
||||
.body(body);
|
||||
|
||||
String s = request.execute().body();
|
||||
log.info("s = {}", s);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密请求参数
|
||||
* @param configDto 配置
|
||||
* @param method 请求方法
|
||||
* @param url 请求地址
|
||||
* @param body 请求报文主体
|
||||
* @return 加密后的报文
|
||||
*
|
||||
* 签名方法
|
||||
* HTTP请求方法\n
|
||||
* URL\n
|
||||
* 请求时间戳\n
|
||||
* 请求随机串\n
|
||||
* 请求报文主体\n
|
||||
*/
|
||||
public static String encryptReqParam(WechatPayConfigDto configDto, String method, String url, String body, long timestamp, String nonce) {
|
||||
String encryptStr = String.format("%s\n%s\n%d\n%s\n%s\n",
|
||||
method, url, timestamp, nonce, body);
|
||||
System.out.println("encryptStr = \n" + encryptStr);
|
||||
|
||||
Config config = WechatConfig.getRsaConfig(configDto);
|
||||
Signer signer = config.createSigner();
|
||||
String signature = signer.sign(encryptStr).getSign();
|
||||
System.out.println("signature = " + signature);
|
||||
return signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取随机串
|
||||
*/
|
||||
private static String getNonceStr() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间戳
|
||||
*/
|
||||
private static long getTimestamp() {
|
||||
return System.currentTimeMillis()/1000;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user