From e6c5b29a47579759dd033c0c520bcf0f986abb59 Mon Sep 17 00:00:00 2001
From: xiaoyong931011 <15274802129@163.com>
Date: Wed, 19 Apr 2023 11:00:28 +0800
Subject: [PATCH] 拉卡拉收银台

---
 src/test/java/cc/mrbird/febs/ProfitTest.java                         |   13 +
 src/api_cert.cer                                                     |   22 ++
 src/api_private_key.pem                                              |   28 +++
 pom.xml                                                              |   11 +
 src/main/java/cc/mrbird/febs/pay/service/LaKaLaService.java          |    9 +
 src/main/java/cc/mrbird/febs/pay/service/impl/LaKaLaServiceImpl.java |  327 ++++++++++++++++++++++++++++++++++++++++
 src/lkl-apigw-v2.cer                                                 |   25 +++
 7 files changed, 431 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index d146f33..4c8219c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,17 @@
     </properties>
 
     <dependencies>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>1.68</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+            <version>1.68</version>
+        </dependency>
         <!--        图片压缩-->
         <dependency>
             <groupId>net.coobird</groupId>
diff --git a/src/api_cert.cer b/src/api_cert.cer
new file mode 100644
index 0000000..b2be121
--- /dev/null
+++ b/src/api_cert.cer
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIGAYSJQP1BMA0GCSqGSIb3DQEBBQUAMGAxFDASBgNVBAMM
+C0xBS0FMQS1MQU9QMQswCQYDVQQGEwJDTjEXMBUGA1UECgwOTGFrYWxhIENvLixM
+dGQxDzANBgNVBAsMBkxLTC1ZRjERMA8GA1UEBwwIc2hhbmdoYWkwHhcNMjIxMTE4
+MDU0MDQ4WhcNMzIxMTE4MDU0MDQ4WjBgMRQwEgYDVQQDDAtMQUtBTEEtTEFPUDEL
+MAkGA1UEBhMCQ04xFzAVBgNVBAoMDkxha2FsYSBDby4sTHRkMQ8wDQYDVQQLDAZM
+S0wtWUYxETAPBgNVBAcMCHNoYW5naGFpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAjf7Ff88dObCuKrMSWh1CwoHn6flW+e9/+CG0iS4Yacix45Tc+f0h
+ddoICfFvh/EgbX1RHJWI7H0Vc/7OO2FsNm6b4HO2RUXTiFQ1nBpOKuH4XtaDssM8
+Yl/4fu4grZ8qFtBDQxh/5cEFGRWNL9Do/h4JnvhOKy776LU5Ochj+PLJLHUGjT0E
+LsqgRIAGKw+gt7yAfvbaUlpy+f0RvP08ekToRyBtqBJfOd8hbosJfHf0zUpmtWoD
+Km4xdGeOWBQNAkysnkGU55EMbfvfNi72LFGmvorr1nDCtnHQ9BMDlq1KabHtKG5I
+NFD3IyBcqKlzc5qFCuayMZWJD5imNE6zNwIDAQABo2AwXjAPBgNVHRMECDAGAQH/
+AgEAMB8GA1UdIwQYMBaAFJDzHLFCYeg8o41u6l8vKkHDGKAoMB0GA1UdDgQWBBSQ
+8xyxQmHoPKONbupfLypBwxigKDALBgNVHQ8EBAMCBsAwDQYJKoZIhvcNAQEFBQAD
+ggEBADSWmpY2kKB2qdFZ1TYd/uPn8ejC1uZIIlBRh07yhQVFABhBSlcGaoBN+Vwv
+rMcqkr4AWX7c63W29+axWVLrwSeFC9ViQqolL3I9cA3PDzmyyzS1T8OLdrr+y7W9
+ixMAnc70O0vEa5vhb/PFu+5qnelSwhIFOz+rgs6ty92gzMHISYBxaPfQGxuTDG3H
+xpL3S+ef/+vOpZjFSv+EvdVPdfPWgMIGFLqaqWEHOKLqpRX/3GAxxSJvWzA+le+q
+IJE7mZF5C+WWd2tn1M/+yHw3PDb2q62MCfe+WmHQNxM/b8JtcC/7lvyhIkOlsi2C
+3nqklUEbOiV7QngV5cuIH2nAS7g=
+-----END CERTIFICATE-----
diff --git a/src/api_private_key.pem b/src/api_private_key.pem
new file mode 100644
index 0000000..d0c646d
--- /dev/null
+++ b/src/api_private_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCN/sV/zx05sK4q
+sxJaHULCgefp+Vb573/4IbSJLhhpyLHjlNz5/SF12ggJ8W+H8SBtfVEclYjsfRVz
+/s47YWw2bpvgc7ZFRdOIVDWcGk4q4fhe1oOywzxiX/h+7iCtnyoW0ENDGH/lwQUZ
+FY0v0Oj+Hgme+E4rLvvotTk5yGP48sksdQaNPQQuyqBEgAYrD6C3vIB+9tpSWnL5
+/RG8/Tx6ROhHIG2oEl853yFuiwl8d/TNSma1agMqbjF0Z45YFA0CTKyeQZTnkQxt
++982LvYsUaa+iuvWcMK2cdD0EwOWrUppse0obkg0UPcjIFyoqXNzmoUK5rIxlYkP
+mKY0TrM3AgMBAAECggEAPbx9hho4rLKCpxIAcqmyMvtkJ7g+9qAI1YtiARrHhoa5
+wSciBJboC2Nmh1wvj71oyfHoaDMjux6PS0WHyQ2MjQX+Q9JLd0bqt6VVQa+2OLLS
+1/kQfZKhGGx9kEJcduBy3kRiWjO2t9/6JXPXVOjRxFqu+C0hX2koIX9ZiCP2Q3A0
+TdlaHillZkwtVQYi85ywPOOKUbl510lIbn5l4dV+jXXDWXAjxoFvgdxtMguXP78m
+cfBsNMit04i5VzhTkG0shUBfpSsdQO3hMlkqYCEUMuh6zIdSZ2xDIEzoOkw7H93k
+r6FNSWxa1kO//roB6Z4niH5BF+oKGY4bkjg0AyYlQQKBgQDbsWJ4UhTira7Hu98V
+j0vy9V5YqmUGOxpxG6gKZnJSNRBZ8qDPXSFoc/ab7Tol7uiNnTcwApOXXZbfEUtg
+y1U6W4ahw5VriZfiV321gkZDP/LazVTvYOTbUrl2YKNnIqRZ6iMehF6shnEPmLZI
+C3MluxCR0t44F8sv2OcNZ+ygEQKBgQCldjTAFKLhBHa3g7Eqc7KJt8SskltZ7sra
+m+BfXVck0l1R1i7kXWb22e0O3x+baiPpoXe6r48wDWXOQ4rEqOVNpLL8zolsn57o
+EZ670ARU8nk7MgFB9JRFuFo2COSqFzMSMaCyHjcjDL56+DP9L7E8LXaML1N6aOw1
+mMTW2Z/mxwKBgQDaMqTtggCyXvR/9i2MmUVCqsco4xvxg1Qw0NomcjfLRF7YJ23m
+ZsYem0Zs+cHOGSoqNOKyMWzrYo3NQb0PBwTAMFVYZwwJwZ/zsxfs5dXpRyNqg5N/
+KUpENzZyx2qjrbl0gGKfFbN+QQ0cA33PsmeMKu47FyeUqLUq8ZASNYzEMQKBgQCk
+4Y0hV68TohoXN3Elh5ODbw/alCHaFX4pqClHfsEnHUYHFfM2d+jx1ipHpopdmcBd
+wRyJeQar8L3hdCblYBTYcWY3TC1fhBSa12whZeHbMKEkHuln6yyR6Wpj7CrJYELx
+P2kN9dQl5j4uVgWgqJTqDbfTbBm4orO3mRuVqdmQ4wKBgHJ0/ba40kzvQCGSv+Nh
+wlDKF23JbD+Wu1yFetylv6n3a9Py1TlxFZ1nPcm10ObFAAKKZEKmBeLrDTgBQP3T
+Zv5R71lRTLIGeT6x5W/CBms/MTbgVWoUw7crq9KE0nEqPvKr/uswAJI05yDN4cEU
+W8/IpLOZtPBO9X73f/kLE8WJ
+-----END PRIVATE KEY-----
diff --git a/src/lkl-apigw-v2.cer b/src/lkl-apigw-v2.cer
new file mode 100644
index 0000000..12723eb
--- /dev/null
+++ b/src/lkl-apigw-v2.cer
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIGAXRTgcMnMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYT
+AkNOMRAwDgYDVQQIDAdCZWlKaW5nMRAwDgYDVQQHDAdCZWlKaW5nMRcwFQYDVQQK
+DA5MYWthbGEgQ28uLEx0ZDEqMCgGA1UEAwwhTGFrYWxhIE9yZ2FuaXphdGlvbiBW
+YWxpZGF0aW9uIENBMB4XDTIwMTAxMDA1MjQxNFoXDTMwMTAwODA1MjQxNFowZTEL
+MAkGA1UEBhMCQ04xEDAOBgNVBAgMB0JlaUppbmcxEDAOBgNVBAcMB0JlaUppbmcx
+FzAVBgNVBAoMDkxha2FsYSBDby4sTHRkMRkwFwYDVQQDDBBBUElHVy5MQUtBTEEu
+Q09NMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt1zHL54HiI8d2sLJ
+lwoQji3/ln0nsvfZ/XVpOjuB+1YR6/0LdxEDMC/hxI6iH2Rm5MjwWz3dmN/6BZeI
+gwGeTOWJUZFARo8UduKrlhC6gWMRpAiiGC8wA8stikc5gYB+UeFVZi/aJ0WN0cpP
+JYCvPBhxhMvhVDnd4hNohnR1L7k0ypuWg0YwGjC25FaNAEFBYP9EYUyCJjE//9Z7
+sMzHR9SJYCqqo6r9bOH9G6sWKuEp+osuAh+kJIxJMHfipw7w3tEcWG0hce9u/el4
+cYJtg8/PPMVoccKmeCzMvarr7jdKP4lenJbtwlgyfs+JgNu60KMUJH8RS72wC9NY
+uFz09wIDAQABo4HVMIHSMIGSBgNVHSMEgYowgYeAFCnH4DkZPR6CZxRn/kIqVsMo
+dJHpoWekZTBjMQswCQYDVQQGEwJDTjEQMA4GA1UECAwHQmVpSmluZzEQMA4GA1UE
+BwwHQmVpSmluZzEXMBUGA1UECgwOTGFrYWxhIENvLixMdGQxFzAVBgNVBAMMDkxh
+a2FsYSBSb290IENBggYBaiUALIowHQYDVR0OBBYEFJ2Kx9YZfmWpkKFnC33C0r5D
+K3rFMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUA
+A4IBAQBZoeU0XyH9O0LGF9R+JyGwfU/O5amoB97VeM+5n9v2z8OCiIJ8eXVGKN9L
+tl9QkpTEanYwK30KkpHcJP1xfVkhPi/cCMgfTWQ5eKYC7Zm16zk7n4CP6IIgZIqm
+TVGsIGKk8RzWseyWPB3lfqMDR52V1tdA1S8lJ7a2Xnpt5M2jkDXoArl3SVSwCb4D
+AmThYhak48M++fUJNYII9JBGRdRGbfJ2GSFdPXgesUL2CwlReQwbW4GZkYGOg9LK
+CNPK6XShlNdvgPv0CCR08KCYRwC3HZ0y1F0NjaKzYdGNPrvOq9lA495ONZCvzYDo
+gmsu/kd6eqxTs/JwdaIYr4sCMg8Z
+-----END CERTIFICATE-----
diff --git a/src/main/java/cc/mrbird/febs/pay/service/LaKaLaService.java b/src/main/java/cc/mrbird/febs/pay/service/LaKaLaService.java
new file mode 100644
index 0000000..451ffde
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/service/LaKaLaService.java
@@ -0,0 +1,9 @@
+package cc.mrbird.febs.pay.service;
+
+public interface LaKaLaService {
+
+    /**
+     * 验证签名
+     */
+    boolean verifyCreateOrder();
+}
diff --git a/src/main/java/cc/mrbird/febs/pay/service/impl/LaKaLaServiceImpl.java b/src/main/java/cc/mrbird/febs/pay/service/impl/LaKaLaServiceImpl.java
new file mode 100644
index 0000000..404782c
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/service/impl/LaKaLaServiceImpl.java
@@ -0,0 +1,327 @@
+package cc.mrbird.febs.pay.service.impl;
+
+import cc.mrbird.febs.pay.service.LaKaLaService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.springframework.stereotype.Service;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+@Slf4j
+@Service
+public class LaKaLaServiceImpl implements LaKaLaService {
+
+
+
+    /**
+     * 字符集固定 utf-8
+     */
+    public static final String ENCODING = "utf-8";
+
+    /**
+     * API schema ,固定 LKLAPI-SHA256withRSA
+     */
+    public final static String SCHEMA = "LKLAPI-SHA256withRSA";
+
+    /**
+     * 接入 appid
+     */
+    public static final String appid = "OP00000418";
+//    public static final String appid = "800000010334001";
+
+    /**
+     * 商户证书序列号,和商户私钥对应
+     */
+//    public static final String mchSerialNo = "017d6ae9ad6e";
+    public static final String mchSerialNo = "01848940fd41";
+
+    /**
+     * 商户证书私钥,用于请求签名
+     */
+    public static final String merchantPrivateKeyPath = "./src/api_private_key.pem";
+
+    /**
+     * 拉卡拉公钥证书,用于response签名验证,务必区分测试环境和生产环境证书
+     */
+    public static final String lklCertificatePath = "./src/lkl-apigw-v2.cer";
+
+    /**
+     * api请求地址
+     */
+    public final static String apiUrl = "https://test.wsmsd.cn/sit";
+
+    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    private static final SecureRandom RANDOM = new SecureRandom();
+
+
+    @Override
+    public boolean verifyCreateOrder() {
+        try {
+            String apiPath = "/api/v3/labs/trans/micropay";
+            String body = "{\n" +
+                    "    \"req_time\": \"20210907150256\",\n" +
+                    "    \"version\": \"3.0\",\n" +
+                    "    \"out_org_code\": \"OP00000003\",\n" +
+                    "    \"req_data\": {\n" +
+                    "        \"merchant_no\": \"8222900701107M5\",\n" +
+                    "        \"term_no\": \"A1062976\",\n" +
+                    "        \"out_trade_no\": \"FD660E1FAA3A4470933CDEDAE1EC1D8E\",\n" +
+                    "        \"auth_code\": \"135178236713755038\",\n" +
+                    "        \"total_amount\": \"23\",\n" +
+                    "        \"location_info\": {\n" +
+                    "            \"request_ip\": \"10.176.1.192\",\n" +
+                    "            \"location\": \"+37.123456789,-121.123456789\"\n" +
+                    "        },\n" +
+                    "        \"out_order_no\": \"08F4542EEC6A4497BC419161747A92FA1\"\n" +
+                    "    }\n" +
+                    "}";
+
+
+            String authorization = getAuthorization(body);
+            HttpResponse response = post(apiUrl + apiPath, body, authorization);
+            if (response.getStatusLine().getStatusCode() != 200) {
+                System.out.println("请求失败,statusCode  " + response.getStatusLine()
+                        + IOUtils.toString(response.getEntity().getContent(), ENCODING));
+                return false;
+            }
+
+            String appid = getHeadValue(response, "Lklapi-Appid");
+            String lklapiSerial = getHeadValue(response, "Lklapi-Serial");
+            String timestamp = getHeadValue(response, "Lklapi-Timestamp");
+            String nonce = getHeadValue(response, "Lklapi-Nonce");
+            String signature = getHeadValue(response, "Lklapi-Signature");
+            String responseStr = IOUtils.toString(response.getEntity().getContent(), ENCODING);
+
+            System.out.println("responseStr  " + responseStr);
+
+            String source = appid + "\n" + lklapiSerial + "\n" + timestamp + "\n" + nonce + "\n" + responseStr + "\n";
+
+            System.out.println("source  " + source);
+
+            X509Certificate lklCertificate = loadCertificate(new FileInputStream(new File(lklCertificatePath)));
+
+            boolean verify = verify(lklCertificate, source.getBytes(ENCODING), signature);
+
+            if (verify) {
+                System.out.println("验签成功");
+                return true;
+            } else {
+                System.err.println("验签失败");
+                return false;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+//    public static void main(String[] args) {
+//        try {
+//            String apiPath = "/api/v3/labs/trans/micropay";
+//
+//            String body = "{\n" +
+//                    "    \"req_time\": \"20210907150256\",\n" +
+//                    "    \"version\": \"3.0\",\n" +
+//                    "    \"out_org_code\": \"OP00000003\",\n" +
+//                    "    \"req_data\": {\n" +
+//                    "        \"merchant_no\": \"822290070111135\",\n" +
+//                    "        \"term_no\": \"29034705\",\n" +
+//                    "        \"out_trade_no\": \"FD660E1FAA3A4470933CDEDAE1EC1D8E\",\n" +
+//                    "        \"auth_code\": \"135178236713755038\",\n" +
+//                    "        \"total_amount\": \"123\",\n" +
+//                    "        \"location_info\": {\n" +
+//                    "            \"request_ip\": \"10.176.1.192\",\n" +
+//                    "            \"location\": \"+37.123456789,-121.123456789\"\n" +
+//                    "        },\n" +
+//                    "        \"out_order_no\": \"08F4542EEC6A4497BC419161747A92FA\"\n" +
+//                    "    }\n" +
+//                    "}";
+//
+//
+//            String authorization = getAuthorization(body);
+//            HttpResponse response = post(apiUrl + apiPath, body, authorization);
+//            if (response.getStatusLine().getStatusCode() != 200) {
+//                System.out.println("请求失败,statusCode  " + response.getStatusLine()
+//                        + IOUtils.toString(response.getEntity().getContent(), ENCODING));
+//                return;
+//            }
+//
+//            String appid = getHeadValue(response, "Lklapi-Appid");
+//            String lklapiSerial = getHeadValue(response, "Lklapi-Serial");
+//            String timestamp = getHeadValue(response, "Lklapi-Timestamp");
+//            String nonce = getHeadValue(response, "Lklapi-Nonce");
+//            String signature = getHeadValue(response, "Lklapi-Signature");
+//            String responseStr = IOUtils.toString(response.getEntity().getContent(), ENCODING);
+//
+//            System.out.println("responseStr  " + responseStr);
+//
+//            String source = appid + "\n" + lklapiSerial + "\n" + timestamp + "\n" + nonce + "\n" + responseStr + "\n";
+//
+//            System.out.println("source  " + source);
+//
+//            X509Certificate lklCertificate = loadCertificate(new FileInputStream(new File(lklCertificatePath)));
+//
+//            boolean verify = verify(lklCertificate, source.getBytes(ENCODING), signature);
+//
+//            if (verify) {
+//                System.out.println("验签成功");
+//
+//                // TODO: 业务处理
+//
+//            } else {
+//                System.err.println("验签失败");
+//            }
+//
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+//
+//    }
+
+    public HttpResponse post(String url, String message, String authorization) throws Exception {
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        X509TrustManager tm = new X509TrustManager() {
+            public X509Certificate[] getAcceptedIssuers() {
+                return null;
+            }
+            public void checkClientTrusted(X509Certificate[] xcs, String str) {}
+            public void checkServerTrusted(X509Certificate[] xcs, String str) {}
+        };
+        HttpClient http = new DefaultHttpClient();
+        ClientConnectionManager ccm = http.getConnectionManager();
+        ctx.init(null, new TrustManager[] { tm }, null);
+        SSLSocketFactory ssf = new SSLSocketFactory(ctx);
+        ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+        SchemeRegistry registry = ccm.getSchemeRegistry();
+        registry.register(new Scheme("https", ssf,443));
+        HttpPost post = new HttpPost(url);
+        StringEntity myEntity = new StringEntity(message, ENCODING);
+        post.setEntity(myEntity);
+        post.setHeader("Authorization", SCHEMA + " " + authorization);
+        post.setHeader("Accept", "application/json");
+        post.setHeader("Content-Type", "application/json");
+        return http.execute(post);
+    }
+
+    protected long generateTimestamp() {
+        return System.currentTimeMillis() / 1000;
+    }
+
+    protected String generateNonceStr() {
+        char[] nonceChars = new char[32];
+        for (int index = 0; index < nonceChars.length; ++index) {
+            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
+        }
+        return new String(nonceChars);
+    }
+
+    public final String getAuthorization(String body) throws IOException {
+        String nonceStr = generateNonceStr();
+        long timestamp = generateTimestamp();
+
+        String message = appid + "\n" + mchSerialNo + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";
+
+        System.out.println("getToken message :  " + message);
+
+        PrivateKey merchantPrivateKey = loadPrivateKey(new FileInputStream(new File(merchantPrivateKeyPath)));
+
+        String signature = this.sign(message.getBytes(ENCODING), merchantPrivateKey);
+
+        String authorization = "appid=\"" + appid + "\"," + "serial_no=\"" + mchSerialNo + "\"," + "timestamp=\""
+                + timestamp + "\"," + "nonce_str=\"" + nonceStr + "\"," + "signature=\"" + signature + "\"";
+        System.out.println("authorization message :" + authorization);
+
+        return authorization;
+    }
+
+    public String sign(byte[] message, PrivateKey privateKey) {
+        try {
+            Signature sign = Signature.getInstance("SHA256withRSA");
+            sign.initSign(privateKey);
+            sign.update(message);
+            return new String(Base64.encodeBase64(sign.sign()));
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
+        } catch (SignatureException e) {
+            throw new RuntimeException("签名计算失败", e);
+        } catch (InvalidKeyException e) {
+            throw new RuntimeException("无效的私钥", e);
+        }
+    }
+
+    private static String getHeadValue(HttpResponse response, String key) {
+        return (response.containsHeader(key)) ? response.getFirstHeader(key).getValue() : "";
+    }
+
+    private static boolean verify(X509Certificate certificate, byte[] message, String signature) {
+        try {
+            Signature sign = Signature.getInstance("SHA256withRSA");
+            sign.initVerify(certificate);
+            sign.update(message);
+            byte[] signatureB = Base64.decodeBase64(signature);
+            return sign.verify(signatureB);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("当前Java环境不支持SHA256withRSA", e);
+        } catch (SignatureException e) {
+            throw new RuntimeException("签名验证过程发生了错误", e);
+        } catch (InvalidKeyException e) {
+            throw new RuntimeException("无效的证书", e);
+        }
+    }
+
+    public static PrivateKey loadPrivateKey(InputStream inputStream) {
+        try {
+            ByteArrayOutputStream array = new ByteArrayOutputStream();
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = inputStream.read(buffer)) != -1) {
+                array.write(buffer, 0, length);
+            }
+
+            String privateKey = array.toString("utf-8").replace("-----BEGIN PRIVATE KEY-----", "")
+                    .replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException("当前Java环境不支持RSA", e);
+        } catch (InvalidKeySpecException e) {
+            throw new RuntimeException("无效的密钥格式");
+        } catch (IOException e) {
+            throw new RuntimeException("无效的密钥");
+        }
+    }
+
+    public static X509Certificate loadCertificate(InputStream inputStream) {
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X509");
+            X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
+
+            cert.checkValidity();
+            return cert;
+        } catch (CertificateExpiredException e) {
+            throw new RuntimeException("证书已过期", e);
+        } catch (CertificateNotYetValidException e) {
+            throw new RuntimeException("证书尚未生效", e);
+        } catch (CertificateException e) {
+            throw new RuntimeException("无效的证书", e);
+        }
+    }
+}
diff --git a/src/test/java/cc/mrbird/febs/ProfitTest.java b/src/test/java/cc/mrbird/febs/ProfitTest.java
index 93679b5..91f2979 100644
--- a/src/test/java/cc/mrbird/febs/ProfitTest.java
+++ b/src/test/java/cc/mrbird/febs/ProfitTest.java
@@ -13,6 +13,7 @@
 import cc.mrbird.febs.mall.service.IMallAchieveService;
 import cc.mrbird.febs.mall.service.IMemberProfitService;
 import cc.mrbird.febs.pay.model.*;
+import cc.mrbird.febs.pay.service.LaKaLaService;
 import cc.mrbird.febs.pay.service.UnipayService;
 import cc.mrbird.febs.rabbit.consumer.AgentConsumer;
 import cc.mrbird.febs.rabbit.producter.AgentProducer;
@@ -80,10 +81,14 @@
 ////
 ////        System.out.println(mallMemberStarIds);
 //    }
-//    @Test
-//    public void agentProfit() {
-////        iApiMallOrderInfoService.changeWallet(665L);
-//    }
+
+
+    @Autowired
+    private LaKaLaService laKaLaService;
+    @Test
+    public void agentProfit() {
+        laKaLaService.verifyCreateOrder();
+    }
 //
 //
 ////    @Test

--
Gitblit v1.9.1