标准收发器客户端
This commit is contained in:
parent
9ec88c3093
commit
3800a19528
@ -6,31 +6,22 @@
|
||||
<artifactId>openapi-sdk</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.5.11</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<java.version>1.8</java.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
<version>1.18.42</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
@ -43,24 +34,19 @@
|
||||
<version>1.83</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.12.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger.core.v3</groupId>
|
||||
<artifactId>swagger-annotations-jakarta</artifactId>
|
||||
<version>2.2.28</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.19.4</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
34
openapi-sdk/src/main/java/com/cisd/openapi/Main.java
Normal file
34
openapi-sdk/src/main/java/com/cisd/openapi/Main.java
Normal file
@ -0,0 +1,34 @@
|
||||
package com.cisd.openapi;
|
||||
|
||||
|
||||
import com.cisd.openapi.config.OkHttpClientHolder;
|
||||
import com.cisd.openapi.config.SignServerProperties;
|
||||
import com.cisd.openapi.config.SignServerPropertiesLoader;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class Main
|
||||
{
|
||||
public static void main(String[] args) {
|
||||
OkHttpClient okHttpClient = OkHttpClientHolder.getClient();
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
SignServerProperties properties = SignServerPropertiesLoader.getProperties();
|
||||
|
||||
SignClient signClient = new SignClient(
|
||||
okHttpClient,
|
||||
objectMapper,
|
||||
properties
|
||||
);
|
||||
|
||||
try {
|
||||
signClient.rawSign("test".getBytes(StandardCharsets.UTF_8), "dn");
|
||||
} catch (Exception e) {
|
||||
System.out.println("签名失败:" + e.getMessage());
|
||||
|
||||
Integer code = signClient.lastReturnCode();
|
||||
System.out.println("lastReturnCode = " + code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.cisd.openapi;
|
||||
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
|
||||
|
||||
@SpringBootApplication
|
||||
@ConfigurationPropertiesScan
|
||||
public class OpenapiSdkApplication
|
||||
{
|
||||
public static void main( String[] args ) {
|
||||
SpringApplication.run(OpenapiSdkApplication.class, args);
|
||||
}
|
||||
}
|
||||
@ -7,14 +7,13 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import okhttp3.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.UUID;
|
||||
|
||||
@Component
|
||||
|
||||
public class SignClient{
|
||||
|
||||
private static final MediaType JSON_MEDIA_TYPE =
|
||||
@ -22,8 +21,8 @@ public class SignClient {
|
||||
|
||||
private final OkHttpClient okHttpClient;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final SignServerProperties properties;
|
||||
|
||||
private final SignServerProperties properties;
|
||||
private final ThreadLocal<Integer> lastReturnCode = new ThreadLocal<>();
|
||||
|
||||
public SignClient(OkHttpClient okHttpClient,
|
||||
@ -44,7 +43,7 @@ public class SignClient {
|
||||
throw new IllegalArgumentException("origBytes不能为空");
|
||||
}
|
||||
|
||||
if (dn == null || dn.isBlank()) {
|
||||
if (dn == null || dn.trim().isEmpty()) {
|
||||
lastReturnCode.set(-100100);
|
||||
throw new IllegalArgumentException("dn不能为空");
|
||||
}
|
||||
@ -101,7 +100,7 @@ public class SignClient {
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("调用rawSign异常", e);
|
||||
throw new RuntimeException("调用rawSign异常:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,12 +114,12 @@ public class SignClient {
|
||||
throw new IllegalArgumentException("origBytes不能为空");
|
||||
}
|
||||
|
||||
if (dn == null || dn.isBlank()) {
|
||||
if (dn == null || dn.trim().isEmpty()) {
|
||||
lastReturnCode.set(-100100);
|
||||
throw new IllegalArgumentException("dn不能为空");
|
||||
}
|
||||
|
||||
if (certStr == null || certStr.isBlank()) {
|
||||
if (certStr == null || certStr.trim().isEmpty()) {
|
||||
lastReturnCode.set(-100100);
|
||||
throw new IllegalArgumentException("certStr签名串不能为空");
|
||||
}
|
||||
@ -190,7 +189,7 @@ public class SignClient {
|
||||
throw new IllegalArgumentException("origBytes不能为空");
|
||||
}
|
||||
|
||||
if (dn == null || dn.isBlank()) {
|
||||
if (dn == null || dn.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("dn不能为空");
|
||||
}
|
||||
|
||||
@ -256,7 +255,7 @@ public class SignClient {
|
||||
throw new IllegalArgumentException("origBytes不能为空");
|
||||
}
|
||||
|
||||
if (certStr == null || certStr.isBlank()) {
|
||||
if (certStr == null || certStr.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("certStr签名串不能为空");
|
||||
}
|
||||
|
||||
@ -326,7 +325,7 @@ public class SignClient {
|
||||
throw new IllegalArgumentException("origBytes不能为空");
|
||||
}
|
||||
|
||||
if (certStr == null || certStr.isBlank()) {
|
||||
if (certStr == null || certStr.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("certStr签名串不能为空");
|
||||
}
|
||||
|
||||
@ -389,7 +388,7 @@ public class SignClient {
|
||||
|
||||
String sessionId = UUID.randomUUID().toString().replace("-", "");
|
||||
|
||||
if (bankCode == null || bankCode.isBlank()) {
|
||||
if (bankCode == null || bankCode.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("origBytes不能为空");
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package com.cisd.openapi.config;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class OkHttpClientHolder {
|
||||
|
||||
private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
|
||||
.connectTimeout(Duration.ofSeconds(5))
|
||||
.writeTimeout(Duration.ofSeconds(10))
|
||||
.readTimeout(Duration.ofSeconds(30))
|
||||
.build();
|
||||
|
||||
private OkHttpClientHolder() {
|
||||
}
|
||||
|
||||
public static OkHttpClient getClient() {
|
||||
return CLIENT;
|
||||
}
|
||||
}
|
||||
@ -1,20 +0,0 @@
|
||||
package com.cisd.openapi.config;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Configuration
|
||||
public class OkHttpConfig {
|
||||
|
||||
@Bean
|
||||
public OkHttpClient okHttpClient() {
|
||||
return new OkHttpClient.Builder()
|
||||
.connectTimeout(Duration.ofSeconds(5))
|
||||
.writeTimeout(Duration.ofSeconds(10))
|
||||
.readTimeout(Duration.ofSeconds(30))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,7 @@
|
||||
package com.cisd.openapi.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "sign-server")
|
||||
@Data
|
||||
public class SignServerProperties {
|
||||
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package com.cisd.openapi.config;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
public class SignServerPropertiesLoader {
|
||||
|
||||
private static final SignServerProperties PROPERTIES = load();
|
||||
|
||||
private SignServerPropertiesLoader() {
|
||||
}
|
||||
|
||||
public static SignServerProperties getProperties() {
|
||||
return PROPERTIES;
|
||||
}
|
||||
|
||||
private static SignServerProperties load() {
|
||||
Properties props = new Properties();
|
||||
|
||||
try (InputStream inputStream = SignServerPropertiesLoader.class
|
||||
.getClassLoader()
|
||||
.getResourceAsStream("sign-server.properties")) {
|
||||
|
||||
if (inputStream == null) {
|
||||
throw new RuntimeException("未找到配置文件 sign-server.properties");
|
||||
}
|
||||
|
||||
props.load(inputStream);
|
||||
|
||||
SignServerProperties config = new SignServerProperties();
|
||||
|
||||
config.setBaseUrl(props.getProperty("sign-server.baseUrl"));
|
||||
config.setApiKey(props.getProperty("sign-server.apiKey"));
|
||||
config.setRawSignPath(props.getProperty("sign-server.rawSignPath"));
|
||||
config.setRawVerifyPath(props.getProperty("sign-server.rawVerifyPath"));
|
||||
config.setDettachedSignPath(props.getProperty("sign-server.dettachedSignPath"));
|
||||
config.setDettachedVerifyPath(props.getProperty("sign-server.dettachedVerifyPath"));
|
||||
config.setDettachedVerifySimplePath(props.getProperty("sign-server.dettachedVerifySimplePath"));
|
||||
config.setUploadCertPath(props.getProperty("sign-server.uploadCertPath"));
|
||||
config.setLastReturnCodePath(props.getProperty("sign-server.lastReturnCodePath"));
|
||||
|
||||
return config;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("加载 sign-server 配置失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
package com.cisd.openapi.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeviceActivateInfoResponse {
|
||||
|
||||
@Schema(description = "设备型号", example = "SYD7108")
|
||||
private String deviceModel;
|
||||
@Schema(description = "设备名称", example = "跨境支付终端一体机")
|
||||
private String deviceName;
|
||||
@Schema(description = "设备版本", example = "1.0.0")
|
||||
private String version;
|
||||
@Schema(description = "设备序列号", example = "1234567890ABCDEF")
|
||||
private String serialNumber;
|
||||
@Schema(description = "设备状态", example = "INITIALIZED")
|
||||
private String deviceStatus;
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package com.cisd.openapi.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeviceActivateRequest {
|
||||
|
||||
private String userId;
|
||||
private String credential;
|
||||
private String activationCode;
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
server:
|
||||
port: 8680
|
||||
|
||||
sign-server:
|
||||
base-url: http://172.1.41.249:8080/api/v1/openapi
|
||||
api-key:
|
||||
raw-sign-path: /rawSign
|
||||
raw-verify-path: /rawVerify
|
||||
dettached-sign-path: /dettachedSign
|
||||
dettached-verify-path: /dettachedVerify
|
||||
dettached-verify-simple-path: /dettachedVerifySimple
|
||||
upload-cert-path: /uploadCert
|
||||
last-return-code-path: /lastReturnCode
|
||||
12
openapi-sdk/src/main/resources/sign-server.properties
Normal file
12
openapi-sdk/src/main/resources/sign-server.properties
Normal file
@ -0,0 +1,12 @@
|
||||
sign-server.baseUrl=http://127.0.0.1:8080
|
||||
sign-server.apiKey=key
|
||||
|
||||
sign-server.rawSignPath=/raw/sign
|
||||
sign-server.rawVerifyPath=/raw/verify
|
||||
|
||||
sign-server.dettachedSignPath=/dettached/sign
|
||||
sign-server.dettachedVerifyPath=/dettached/verify
|
||||
sign-server.dettachedVerifySimplePath=/dettached/verify/simple
|
||||
|
||||
sign-server.uploadCertPath=/cert/upload
|
||||
sign-server.lastReturnCodePath=/last/return/code
|
||||
@ -1,90 +0,0 @@
|
||||
package com.cisd.openapi;
|
||||
|
||||
import com.cisd.openapi.dto.GenericCertificate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("test")
|
||||
class SignClientTest {
|
||||
|
||||
@Autowired
|
||||
private SignClient signClient;
|
||||
|
||||
private final byte[] origBytes = "11111111".getBytes();
|
||||
private final String dn = "C=CN,ST=Beijing,L=Beijing,O=Initial Org,OU=Initial OU,CN=Initial Entity";
|
||||
|
||||
|
||||
@Test
|
||||
void testRawSign() {
|
||||
String signature = signClient.rawSign(origBytes, dn);
|
||||
System.out.println("rawSign: " + signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRawVerify() {
|
||||
String signature = signClient.rawSign(origBytes, dn);
|
||||
boolean verified = signClient.rawVerify(origBytes, signature, dn);
|
||||
System.out.println("rawVerify: " + verified);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDettachedSign() {
|
||||
String dettachedSig = signClient.dettachedSign(origBytes, dn);
|
||||
System.out.println("dettachedSign: " + dettachedSig);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
void testDettachedVerify() {
|
||||
String dettachedSignature = signClient.dettachedSign(origBytes, dn);
|
||||
GenericCertificate cert = signClient.dettachedVerify(origBytes, dettachedSignature);
|
||||
System.out.println("dettachedVerify 证书主题: " + cert.getSubject());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testDettachedVerifySimple() {
|
||||
String dettachedSig = signClient.dettachedSign(origBytes, dn);
|
||||
GenericCertificate cert = signClient.dettachedVerifySimple(origBytes, dettachedSig);
|
||||
System.out.println("dettachedVerifySimple 证书主题: " + cert.getSubject());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUploadCert() throws Exception {
|
||||
String certFilePath = "path";
|
||||
X509Certificate certificate;
|
||||
try {
|
||||
certificate = loadCertificate(certFilePath);
|
||||
} catch (Exception e) {
|
||||
System.out.println("加载失败" + certFilePath);
|
||||
return;
|
||||
}
|
||||
boolean success = signClient.uploadCert("bankCode", certificate);
|
||||
System.out.println("uploadCert : " + success);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLastReturnCode() {
|
||||
Integer code = signClient.lastReturnCode();
|
||||
System.out.println("lastReturnCode: " + code);
|
||||
}
|
||||
|
||||
|
||||
private X509Certificate loadCertificate(String filePath) throws Exception {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
try (FileInputStream fis = new FileInputStream(filePath)) {
|
||||
return (X509Certificate) cf.generateCertificate(fis);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
sign-server:
|
||||
base-url: http://172.1.41.249:8080/api/v1/openapi
|
||||
api-key:
|
||||
raw-sign-path: /rawSign
|
||||
raw-verify-path: /rawVerify
|
||||
dettached-sign-path: /dettachedSign
|
||||
dettached-verify-path: /dettachedVerify
|
||||
dettached-verify-simple-path: /dettachedVerifySimple
|
||||
upload-cert-path: /uploadCert
|
||||
last-return-code-path: /lastReturnCode
|
||||
Loading…
Reference in New Issue
Block a user