微信请求加密
This commit is contained in:
@@ -18,7 +18,7 @@ public class WechatConfig {
|
|||||||
* @param dto 微信支付配置
|
* @param dto 微信支付配置
|
||||||
* @return 微信支付配置
|
* @return 微信支付配置
|
||||||
*/
|
*/
|
||||||
public static Config getConfig(WechatPayConfigDto dto) {
|
public static Config getRsaConfig(WechatPayConfigDto dto) {
|
||||||
return new RSAPublicKeyConfig.Builder()
|
return new RSAPublicKeyConfig.Builder()
|
||||||
.merchantId(dto.getMerchantId())
|
.merchantId(dto.getMerchantId())
|
||||||
.privateKey(dto.getPrivateKey())
|
.privateKey(dto.getPrivateKey())
|
||||||
@@ -41,7 +41,7 @@ public class WechatConfig {
|
|||||||
* @return 文件上传服务
|
* @return 文件上传服务
|
||||||
*/
|
*/
|
||||||
public static FileUploadService getFileUploadService(WechatPayConfigDto dto) {
|
public static FileUploadService getFileUploadService(WechatPayConfigDto dto) {
|
||||||
return getFileUploadService(getConfig(dto));
|
return getFileUploadService(getRsaConfig(dto));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,45 @@
|
|||||||
package com.czg.wechat;
|
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.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Base64;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付加解密
|
* 微信支付加解密
|
||||||
* @author yjjie
|
* @author yjjie
|
||||||
* @date 2025/12/26 10:58
|
* @date 2025/12/26 10:58
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class WechatEncrypt {
|
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 {
|
public static String getFileBytesSha256(byte[] input) throws NoSuchAlgorithmException {
|
||||||
return bytesToHex(calculateSha256(input));
|
return bytesToHex(calculateSha256(input));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,15 @@ package com.czg.wechat;
|
|||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.JSONWriter;
|
import com.alibaba.fastjson2.JSONWriter;
|
||||||
import com.czg.wechat.dto.config.WechatPayConfigDto;
|
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.FileUploadService;
|
||||||
import com.wechat.pay.java.service.file.model.FileUploadResponse;
|
import com.wechat.pay.java.service.file.model.FileUploadResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -12,6 +20,8 @@ import java.net.URI;
|
|||||||
import java.net.http.HttpClient;
|
import java.net.http.HttpClient;
|
||||||
import java.net.http.HttpRequest;
|
import java.net.http.HttpRequest;
|
||||||
import java.net.http.HttpResponse;
|
import java.net.http.HttpResponse;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付进件 管理
|
* 微信支付进件 管理
|
||||||
@@ -22,6 +32,21 @@ import java.net.http.HttpResponse;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class WechatEntryManager {
|
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) {
|
public static String uploadImage(WechatPayConfigDto configDto, String url) {
|
||||||
// 校验入参
|
// 校验入参
|
||||||
if (configDto == null || url == null || url.trim().isEmpty()) {
|
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");
|
// String string = uploadImage(dto, "https://czg-qr-order.oss-cn-beijing.aliyuncs.com/indexs/shuangbackground.png");
|
||||||
// log.info("图片上传成功:{}", string);
|
// log.info("图片上传成功:{}", string);
|
||||||
|
|
||||||
WechatEntryReqDto reqDto = new WechatEntryReqDto();
|
Config config = WechatConfig.getRsaConfig(dto);
|
||||||
System.out.println(JSONObject.toJSONString(reqDto, JSONWriter.Feature.IgnoreEmpty));
|
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