feat:封装客户端通知处理
parent
3c375eba8f
commit
4615b3fccd
|
|
@ -1,11 +1,19 @@
|
||||||
package com.czcb.scfs.api.core;
|
package com.czcb.scfs.api.core;
|
||||||
|
|
||||||
|
import com.czcb.scfs.api.core.cipher.PrivacyEncryptor;
|
||||||
|
import com.czcb.scfs.api.core.cipher.SecretCipher;
|
||||||
import com.czcb.scfs.api.core.http.*;
|
import com.czcb.scfs.api.core.http.*;
|
||||||
import com.czcb.scfs.api.core.util.Extractor;
|
import com.czcb.scfs.api.core.util.Extractor;
|
||||||
import com.czcb.scfs.api.core.util.Json;
|
import com.czcb.scfs.api.core.util.Json;
|
||||||
|
import com.czcb.scfs.api.core.util.Strings;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static com.czcb.scfs.api.core.Constants.BANK_CERTIFICATE_SERIAL;
|
||||||
|
import static com.czcb.scfs.api.core.Constants.SECRET_KEY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author wangwei
|
* @author wangwei
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
|
|
@ -70,4 +78,65 @@ public interface ApiClient {
|
||||||
.build();
|
.build();
|
||||||
return exchange(httpRequest, responseClass);
|
return exchange(httpRequest, responseClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知请求参数解密
|
||||||
|
*
|
||||||
|
* @param requestJsonStr 请求参数JSON字符串
|
||||||
|
* @param requestClass 请求参数Class
|
||||||
|
* @return 请求参数
|
||||||
|
* @author H.T
|
||||||
|
* @since 2026/5/19
|
||||||
|
*/
|
||||||
|
default <T> T decryptRequest(String requestJsonStr, Class<T> requestClass) {
|
||||||
|
// 解析JSON
|
||||||
|
JsonObject requestJson = JsonParser.parseString(requestJsonStr).getAsJsonObject();
|
||||||
|
// 提取请求头
|
||||||
|
JsonObject headerJson = requestJson.getAsJsonObject("header");
|
||||||
|
// SECRET_KEY密钥 密文
|
||||||
|
String secretKeyCiphertext = headerJson.get(SECRET_KEY).getAsString();
|
||||||
|
// 非对称解密后SECRET_KEY密钥 明文
|
||||||
|
String secretKeyPlain = getProfile().getPrivacy().getDecryptor().decrypt(secretKeyCiphertext);
|
||||||
|
// 提取请求体原始body 密文
|
||||||
|
String bodyCiphertext = requestJson.get("body").getAsString();
|
||||||
|
// 对称解密后body 明文
|
||||||
|
String bodyPlain = getProfile().getPrivacy().getSecretCipher().decrypt(Strings.toBytes(secretKeyPlain), Strings.toBytes(bodyCiphertext));
|
||||||
|
return Json.fromJson(bodyPlain, requestClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知应答参数加密
|
||||||
|
*
|
||||||
|
* @param responseObject 应答参数Object
|
||||||
|
* @return 应答完整JSON
|
||||||
|
* @author H.T
|
||||||
|
* @since 2026/5/19
|
||||||
|
*/
|
||||||
|
default String encryptResponse(Object responseObject) {
|
||||||
|
// 序列化body 明文
|
||||||
|
String responseJsonStr = Json.toJson(responseObject);
|
||||||
|
// 对称加密器
|
||||||
|
SecretCipher cipher = getProfile().getPrivacy().getSecretCipher();
|
||||||
|
// 生成SECRET_KEY密钥 明文
|
||||||
|
byte[] secretKeyPlain = cipher.getSecretKey();
|
||||||
|
// 非对称加密器
|
||||||
|
PrivacyEncryptor encryptor = getProfile().getPrivacy().getEncryptor();
|
||||||
|
// 非对称加密后SECRET_KEY密钥 密文
|
||||||
|
String secretKeyCiphertext = encryptor.encrypt(Strings.toStr(secretKeyPlain));
|
||||||
|
// 对称加密后body 密文
|
||||||
|
String bodyCiphertext = cipher.encrypt(secretKeyPlain, Strings.toBytes(responseJsonStr));
|
||||||
|
// 应答JSON串
|
||||||
|
JsonObject responseJson = new JsonObject();
|
||||||
|
// 应答头JSON串
|
||||||
|
JsonObject headerJson = new JsonObject();
|
||||||
|
// 加密后的密钥放入到请求头
|
||||||
|
headerJson.addProperty(SECRET_KEY, secretKeyCiphertext);
|
||||||
|
// 加密证书序列号放入到请求头
|
||||||
|
headerJson.addProperty(BANK_CERTIFICATE_SERIAL, encryptor.getCertificateSerial());
|
||||||
|
// 添加应答头
|
||||||
|
responseJson.add("header", headerJson);
|
||||||
|
// 添加body
|
||||||
|
responseJson.addProperty("body", bodyCiphertext);
|
||||||
|
return responseJson.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.czcb.scfs.api.service.handle;
|
||||||
|
|
||||||
|
import com.czcb.scfs.api.core.ApiClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端通知处理
|
||||||
|
*
|
||||||
|
* @author H.T
|
||||||
|
* @since 2026-05-19
|
||||||
|
*/
|
||||||
|
public class NotifyHandler {
|
||||||
|
|
||||||
|
private final ApiClient apiClient;
|
||||||
|
|
||||||
|
public NotifyHandler(ApiClient apiClient) {
|
||||||
|
this.apiClient = apiClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知请求参数解密
|
||||||
|
*
|
||||||
|
* @param requestJsonStr 请求参数JSON字符串
|
||||||
|
* @param requestClass 请求参数Class
|
||||||
|
* @return 请求参数
|
||||||
|
* @author H.T
|
||||||
|
* @since 2026/5/19
|
||||||
|
*/
|
||||||
|
public <T> T decryptRequest(String requestJsonStr, Class<T> requestClass) {
|
||||||
|
return apiClient.decryptRequest(requestJsonStr, requestClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知应答参数加密
|
||||||
|
*
|
||||||
|
* @param responseObject 应答参数Object
|
||||||
|
* @return 应答完整JSON
|
||||||
|
* @author H.T
|
||||||
|
* @since 2026/5/19
|
||||||
|
*/
|
||||||
|
public String encryptResponse(Object responseObject) {
|
||||||
|
return apiClient.encryptResponse(responseObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import com.czcb.scfs.api.core.ApiClient;
|
||||||
import com.czcb.scfs.api.core.Profile;
|
import com.czcb.scfs.api.core.Profile;
|
||||||
import com.czcb.scfs.api.core.http.ApiClientBuilder;
|
import com.czcb.scfs.api.core.http.ApiClientBuilder;
|
||||||
import com.czcb.scfs.api.service.echo.EchoService;
|
import com.czcb.scfs.api.service.echo.EchoService;
|
||||||
|
import com.czcb.scfs.api.service.handle.NotifyHandler;
|
||||||
import com.czcb.scfs.api.service.v2.account.AccountService;
|
import com.czcb.scfs.api.service.v2.account.AccountService;
|
||||||
import com.czcb.scfs.api.service.v2.ar.*;
|
import com.czcb.scfs.api.service.v2.ar.*;
|
||||||
import com.czcb.scfs.api.service.v2.bills.BillService;
|
import com.czcb.scfs.api.service.v2.bills.BillService;
|
||||||
|
|
@ -348,4 +349,14 @@ public class ScfsAutoConfiguration {
|
||||||
public SummaryOrderService summaryOrderService(ApiClient apiClient) {
|
public SummaryOrderService summaryOrderService(ApiClient apiClient) {
|
||||||
return new SummaryOrderService(apiClient);
|
return new SummaryOrderService(apiClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端通知处理
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
@ConditionalOnClass(NotifyHandler.class)
|
||||||
|
public NotifyHandler notifyHandler(ApiClient apiClient) {
|
||||||
|
return new NotifyHandler(apiClient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.czcb.scfs.api.test.service;
|
||||||
|
|
||||||
|
import com.czcb.scfs.api.service.handle.NotifyHandler;
|
||||||
|
import com.czcb.scfs.api.service.v2.pay.model.OfflineRechargeRefundRequest;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import static com.czcb.scfs.api.core.Constants.SECRET_KEY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端通知处理Test
|
||||||
|
*
|
||||||
|
* @author H.T
|
||||||
|
* @since 2026-05-19
|
||||||
|
*/
|
||||||
|
@SpringBootTest
|
||||||
|
class NotifyHandlerTest {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private NotifyHandler notifyHandler;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void decryptRequest() throws JSONException {
|
||||||
|
JSONObject jsonObject = new JSONObject();
|
||||||
|
jsonObject.put("body", "n/mpGUWGb9HpNvtyM1U7s8yTHP1oMBqAR4U+hTvw0gMtHFcXdvltJ/Dcw+U079FFiClExTP+d6skwnVVCftRXOfWlwOtQ9Ws1Soq7m+Gpr5CPuaMsRZeqzM4QL/RWhvGX36yE8BWZfICIBgmF8GdBd12iOjd6UO5qrt6ZZjqC0wr0gWpU9HK4JdcbJhaWOg45q1a3A76DVVTOsavwIfjF742WrVg3t42/2NsP7GNkMBJyuv1XHJQGgAUGP0Q6l5vPNU8nAFxyC+gKX/CyY+hmsqAr+jNOTVrcVj/AApQ3zf/pI1/zInVR6cq76ulv/5U2rBFrTJpZk6hpiFgr8/OfRYzrn0dQ/0QaSLFG8L0prIkMvV/");
|
||||||
|
|
||||||
|
JSONObject headerJson = new JSONObject();
|
||||||
|
headerJson.put(SECRET_KEY, "MHoCIQC1ZJNfSItiTtyGrPY4xxHvTKiFMxSEJtlWlG+iKGGMnQIhAM4hAOEdCoKDZS/GH/l/kxtgmtC4we2Cxtt4SXQroxkOBCA2GwL0sfxtqc8I6MU6hbmgby1xEHAq61l+3OiOZOkKOAQQBPDf5gnp3cB701SGw9i7cg==");
|
||||||
|
jsonObject.put("header", headerJson);
|
||||||
|
|
||||||
|
|
||||||
|
System.err.println(jsonObject);
|
||||||
|
System.out.println(notifyHandler.decryptRequest(jsonObject.toString(), OfflineRechargeRefundRequest.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void encryptResponse() {
|
||||||
|
System.out.println(notifyHandler.encryptResponse("通知成功"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue