소스 검색

慧用工签名已过

skyfffire 1 개월 전
부모
커밋
78709d5df1

+ 13 - 0
src/main/java/common/utils/hyg/AESUtils.java

@@ -16,6 +16,19 @@ public class AESUtils {
     // 定义加密算法
     private static final String ALGORITHM = "AES";
 
+    /**
+     * 根据加密后的十六进制字符串和密钥进行解密
+     *
+     * @param contentHex 加密后的十六进制字符串
+     * @return 解密后的原始字符串
+     * @throws Exception 如果解密过程中发生错误
+     */
+    public static String decryptByHex(String contentHex) throws Exception {
+        String key = System.getenv("HYG_AES_KEY");
+        // 调用内部解密方法
+        return decryptByHex(contentHex, key);
+    }
+
     /**
      * 根据加密后的十六进制字符串和密钥进行解密
      *

+ 97 - 0
src/main/java/common/utils/hyg/HygSDK.java

@@ -0,0 +1,97 @@
+package common.utils.hyg;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.jfinal.kit.HttpKit;
+import com.jfinal.kit.StrKit;
+
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+public class HygSDK {
+    private final static String DOMAIN = System.getenv("HYG_DOMAIN");
+    private final static String RSA_PUBLIC_KEY = System.getenv("HYG_RSA_PUBLIC_KEY");
+    private final static String RSA_PRIVATE_KEY = System.getenv("HYG_RSA_PRIVATE_KEY");
+    private final static String AES_KEY = System.getenv("HYG_AES_KEY");
+    private final static String COOPERATOR_ID = System.getenv("HYG_COOPERATOR_ID");
+
+    // API 路径常量
+    private static final String FIND_DETAILS_API = "/api/v2/hire/worker/findDetails";
+
+    /**
+     * 自由职业者信息详情查询接口
+     * 接口地址: https://${domain}/api/v2/hire/worker/findDetails
+     *
+     * @param workerId 自由职业者ID
+     * @return JSONObject 包含statusCode, statusText, data 等信息的响应
+     * @throws Exception 如果请求或签名发生错误
+     */
+    public static JSONObject findWorkerDetails(String workerId) throws Exception {
+        // 构建业务请求参数 Map
+        Map<String, Object> bizParams = new HashMap<>();
+        bizParams.put("workerId", workerId);                // 自由职业者ID
+
+        return HygSDK.invokeApi(FIND_DETAILS_API, bizParams);
+    }
+
+    /**
+     * 可以添加一个公共的请求方法,处理签名、加密、响应解析等通用逻辑
+     * @param apiPath 例如 FIND_DETAILS_API
+     * @param bizParams 业务参数,不包含cooperatorId, timestamp, sign
+     * @return
+     * @throws Exception
+     */
+    public static JSONObject invokeApi(String apiPath, Map<String, Object> bizParams) throws Exception {
+        // 加载固定参数
+        Map<String, Object> fullParams = new HashMap<>();
+        fullParams.put("cooperatorId", COOPERATOR_ID);
+        fullParams.putAll(bizParams); // 添加传入的业务参数
+
+        // 生成时间戳
+        String timestamp = String.valueOf(System.currentTimeMillis());
+        fullParams.put("timestamp", timestamp);
+
+        // 签名
+        String sortedParamString = RSAUtils.sortParam(fullParams);
+        System.out.println(sortedParamString);
+        String sign = RSAUtils.sign(sortedParamString.getBytes(StandardCharsets.UTF_8), RSA_PRIVATE_KEY);
+        fullParams.put("sign", sign);
+
+        // 构建请求 URL
+        String requestUrl = DOMAIN + apiPath;
+        
+        // 构造最终请求
+        Map<String, Object> finalParams = new HashMap<>();
+        finalParams.put("cooperatorId", COOPERATOR_ID);
+        String jsonStr = JSONObject.toJSONString(fullParams);
+        System.out.println(jsonStr);
+        finalParams.put("businessBody", AESUtils.encrypt2Hex(jsonStr, AES_KEY));
+
+        // 请求头
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Content-Type", "application/json");
+        
+        // 发送请求
+        String postParams = JSON.toJSONString(finalParams);
+        String responseBody = HttpKit.post(requestUrl, null, postParams, headers);
+
+        if (StrKit.isBlank(responseBody)) {
+            throw new RuntimeException("API响应为空");
+        }
+        
+        // 解密返回值
+        JSONObject responseJson = JSON.parseObject(responseBody);
+        responseJson.put("data", JSONObject.parseObject(AESUtils.decryptByHex(responseJson.getString("data"))));
+        
+        return responseJson;
+    }
+
+    public static void main(String[] args) {
+        try {
+            System.out.println(HygSDK.findWorkerDetails("W1417202514024992768"));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 43 - 65
src/main/java/common/utils/hyg/RSAUtils.java

@@ -1,6 +1,6 @@
 package common.utils.hyg;
 
-import com.jfinal.kit.StrKit; // 仍然保留,因为您有 JFinal 框架
+import com.jfinal.kit.StrKit;
 
 import javax.crypto.Cipher;
 import java.io.ByteArrayOutputStream;
@@ -10,7 +10,7 @@ import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
-import java.util.*; // 导入 Java 8+ 的标准 Base64 类
+import java.util.*;
 
 public class RSAUtils {
     // 密钥算法
@@ -20,11 +20,11 @@ public class RSAUtils {
     // 加密/解密算法及填充方式, RSA默认使用PKCS1Padding
     public static final String CIPHER_ALGORITHM = "RSA/ECB/PKCS1Padding";
 
-    // 密钥长度,这里使用1024位,也可以是2048等
-    private static final int KEY_SIZE = 1024;
+    // 密钥长度,这里使用1024位
+    private static final int KEY_SIZE = 1024; // 也可以是 2048 等
 
     // 存储公钥和私钥的Map键
-    private static final String PUBLIC_KEY = "RSAPublicKey";
+    private static final String PUBLIC_KEY = "RSAPublicyKey";
     private static final String PRIVATE_KEY = "RSAPrivateKey";
 
     // RSA加密最大分段大小 (对于1024位RSA密钥,PKCS1Padding填充,最大加密长度为128-11=117字节)
@@ -44,7 +44,7 @@ public class RSAUtils {
      */
     public static Map<String, Key> genKeyPair() throws Exception {
         KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
-        keyPairGen.initialize(KEY_SIZE); // 初始化密钥长度
+        keyPairGen.initialize(KEY_SIZE);
         KeyPair keyPair = keyPairGen.generateKeyPair();
         RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
         RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
@@ -63,14 +63,15 @@ public class RSAUtils {
      * @throws Exception 如果签名过程中发生错误
      */
     public static String sign(byte[] data, String privateKey) throws Exception {
-        byte[] keyBytes = Base64.getDecoder().decode(privateKey); // 改用 java.util.Base64
+        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
-        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
+        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); // 可能会在此处抛出 InvalidKeySpecException
+
         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
         signature.initSign(privateK);
         signature.update(data);
-        return Base64.getEncoder().encodeToString(signature.sign()); // 改用 java.util.Base64
+        return Base64.getEncoder().encodeToString(signature.sign());
     }
 
     /**
@@ -83,14 +84,15 @@ public class RSAUtils {
      * @throws Exception 如果验证签名过程中发生错误
      */
     public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
-        byte[] keyBytes = Base64.getDecoder().decode(publicKey); // 改用 java.util.Base64
+        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
         X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         PublicKey publicK = keyFactory.generatePublic(keySpec);
+
         Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
         signature.initVerify(publicK);
         signature.update(data);
-        return signature.verify(Base64.getDecoder().decode(sign)); // 改用 java.util.Base64
+        return signature.verify(Base64.getDecoder().decode(sign));
     }
 
     /**
@@ -102,13 +104,13 @@ public class RSAUtils {
      * @throws Exception 如果解密过程中发生错误
      */
     public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
-        byte[] keyBytes = Base64.getDecoder().decode(privateKey); // 改用 java.util.Base64
+        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
 
-        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 明确指定算法和填充方式
-        cipher.init(Cipher.DECRYPT_MODE, privateK); // 解密模式
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(Cipher.DECRYPT_MODE, privateK);
 
         int inputLen = encryptedData.length;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -116,13 +118,10 @@ public class RSAUtils {
         byte[] cache;
         // 对数据分段解密
         while (inputLen - offSet > 0) {
-            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
-                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
-            } else {
-                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
-            }
+            int actualBlockSize = (inputLen - offSet > MAX_DECRYPT_BLOCK) ? MAX_DECRYPT_BLOCK : (inputLen - offSet);
+            cache = cipher.doFinal(encryptedData, offSet, actualBlockSize);
             out.write(cache, 0, cache.length);
-            offSet += cache.length; // 实际解密字节数
+            offSet += actualBlockSize; // 修正 offSet 推进逻辑
         }
         byte[] decryptedData = out.toByteArray();
         out.close();
@@ -139,13 +138,13 @@ public class RSAUtils {
      * @throws Exception 如果解密过程中发生错误
      */
     public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
-        byte[] keyBytes = Base64.getDecoder().decode(publicKey); // 改用 java.util.Base64
+        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         Key publicK = keyFactory.generatePublic(x509KeySpec);
 
-        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 明确指定算法和填充方式
-        cipher.init(Cipher.DECRYPT_MODE, publicK); // 解密模式
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(Cipher.DECRYPT_MODE, publicK);
 
         int inputLen = encryptedData.length;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -153,13 +152,10 @@ public class RSAUtils {
         byte[] cache;
         // 对数据分段解密
         while (inputLen - offSet > 0) {
-            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
-                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
-            } else {
-                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
-            }
+            int actualBlockSize = (inputLen - offSet > MAX_DECRYPT_BLOCK) ? MAX_DECRYPT_BLOCK : (inputLen - offSet);
+            cache = cipher.doFinal(encryptedData, offSet, actualBlockSize);
             out.write(cache, 0, cache.length);
-            offSet += cache.length; // 实际解密字节数
+            offSet += actualBlockSize; // 修正 offSet 推进逻辑
         }
         byte[] decryptedData = out.toByteArray();
         out.close();
@@ -175,13 +171,13 @@ public class RSAUtils {
      * @throws Exception 如果加密过程中发生错误
      */
     public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
-        byte[] keyBytes = Base64.getDecoder().decode(publicKey); // 改用 java.util.Base64
+        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
         X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         Key publicK = keyFactory.generatePublic(x509KeySpec);
 
-        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 明确指定算法和填充方式
-        cipher.init(Cipher.ENCRYPT_MODE, publicK); // 加密模式
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(Cipher.ENCRYPT_MODE, publicK);
 
         int inputLen = data.length;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -189,15 +185,10 @@ public class RSAUtils {
         byte[] cache;
         // 对数据分段加密
         while (inputLen - offSet > 0) {
-            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
-                // 如果剩余数据大于最大加密块,加密一个完整块
-                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
-            } else {
-                // 加密剩余的所有数据
-                cache = cipher.doFinal(data, offSet, inputLen - offSet);
-            }
+            int actualBlockSize = (inputLen - offSet > MAX_ENCRYPT_BLOCK) ? MAX_ENCRYPT_BLOCK : (inputLen - offSet);
+            cache = cipher.doFinal(data, offSet, actualBlockSize);
             out.write(cache, 0, cache.length);
-            offSet += MAX_ENCRYPT_BLOCK; // 每次偏移一个加密块大小
+            offSet += actualBlockSize; // 修正 offSet 推进逻辑 (这里是 inputLen)
         }
         byte[] encryptedData = out.toByteArray();
         out.close();
@@ -214,13 +205,13 @@ public class RSAUtils {
      * @throws Exception 如果加密过程中发生错误
      */
     public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
-        byte[] keyBytes = Base64.getDecoder().decode(privateKey); // 改用 java.util.Base64
+        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
         PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
         KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
         Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
 
-        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 明确指定算法和填充方式
-        cipher.init(Cipher.ENCRYPT_MODE, privateK); // 加密模式
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(Cipher.ENCRYPT_MODE, privateK);
 
         int inputLen = data.length;
         ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -228,13 +219,10 @@ public class RSAUtils {
         byte[] cache;
         // 对数据分段加密
         while (inputLen - offSet > 0) {
-            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
-                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
-            } else {
-                cache = cipher.doFinal(data, offSet, inputLen - offSet);
-            }
+            int actualBlockSize = (inputLen - offSet > MAX_ENCRYPT_BLOCK) ? MAX_ENCRYPT_BLOCK : (inputLen - offSet);
+            cache = cipher.doFinal(data, offSet, actualBlockSize);
             out.write(cache, 0, cache.length);
-            offSet += MAX_ENCRYPT_BLOCK; // 每次偏移一个加密块大小
+            offSet += actualBlockSize; // 修正 offSet 推进逻辑 (这里是 inputLen)
         }
         byte[] encryptedData = out.toByteArray();
         out.close();
@@ -250,7 +238,7 @@ public class RSAUtils {
      */
     public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {
         Key key = keyMap.get(PRIVATE_KEY);
-        return Base64.getEncoder().encodeToString(key.getEncoded()); // 改用 java.util.Base64
+        return Base64.getEncoder().encodeToString(key.getEncoded());
     }
 
     /**
@@ -262,7 +250,7 @@ public class RSAUtils {
      */
     public static String getPublicKey(Map<String, Key> keyMap) throws Exception {
         Key key = keyMap.get(PUBLIC_KEY);
-        return Base64.getEncoder().encodeToString(key.getEncoded()); // 改用 java.util.Base64
+        return Base64.getEncoder().encodeToString(key.getEncoded());
     }
 
     /**
@@ -276,24 +264,15 @@ public class RSAUtils {
         if (paramMap == null || paramMap.isEmpty()) {
             return "";
         }
-        // 将Map的Entry转换为List,以便排序
         List<Map.Entry<String, Object>> list = new ArrayList<>(paramMap.entrySet());
-
-        // 使用Comparator按照Key的ASCII值进行排序
         Collections.sort(list, Comparator.comparing(Map.Entry::getKey));
 
-        // 拼接字符串
         StringBuilder sb = new StringBuilder();
         for (Map.Entry<String, Object> item : list) {
-            // 过滤空值,通常规则是空值不参与签名
-            // StrKit.isBlank() 会检查 null, "", "   "
-            if (!StrKit.isBlank(item.getKey()) && item.getValue() != null) { // value不能是null
-                // 如果值是空字符串,根据业务需要决定是否拼接
-                // 这里按原逻辑,如果值是空字符串,也会拼接
+            if (!StrKit.isBlank(item.getKey()) && item.getValue() != null) {
                 sb.append(item.getKey()).append("=").append(item.getValue()).append("&");
             }
         }
-        // 移除末尾多余的'&'
         if (sb.length() > 0) {
             return sb.substring(0, sb.length() - 1);
         }
@@ -358,7 +337,6 @@ public class RSAUtils {
                 boolean wrongSignVerified = verify(dataBytes, publicKey, wrongSign);
                 System.out.println("验证签名结果 (正确数据与错误签名): " + wrongSignVerified);
             } catch (IllegalArgumentException e) {
-                // java.util.Base64.getDecoder().decode() 在遇到非法Base64字符串时会抛出 IllegalArgumentException
                 System.out.println("验证签名结果 (正确数据与错误签名): Base64解码错误,签名非法。");
             }
 
@@ -366,12 +344,12 @@ public class RSAUtils {
 
             // 5. sortParam 方法测试
             System.out.println("--- sortParam 方法测试 ---");
-            Map<String, Object> params = new TreeMap<>(); // 使用TreeMap方便观察排序
+            Map<String, Object> params = new TreeMap<>();
             params.put("appKey", "123");
             params.put("timestamp", System.currentTimeMillis());
             params.put("paramA", "valueA");
             params.put("paramC", "valueC");
-            params.put("paramB", null); // 测试null值
+            params.put("paramB", null);
             params.put("paramD", ""); // 测试空字符串
 
             String sortedAndConcatenated = sortParam(params);
@@ -385,4 +363,4 @@ public class RSAUtils {
             e.printStackTrace();
         }
     }
-}
+}

+ 1 - 1
src/main/java/modules/user/UserController.java

@@ -232,7 +232,7 @@ public class UserController extends MyController {
         String businessBodyEncryptedHex = requestBodyJson.getString("businessBody");
 
         try {
-            String body = AESUtils.decryptByHex(businessBodyEncryptedHex, System.getenv("HYG_AES_SECRET_KEY"));
+            String body = AESUtils.decryptByHex(businessBodyEncryptedHex);
             JSONObject businessBody = JSONObject.parseObject(body);
             
             String workerId = businessBody.getString("workerId");