From e99dcf16787af69c69d16afcd92b6bf8922eede1 Mon Sep 17 00:00:00 2001
From: seatonwan9
Date: 星期四, 28 八月 2025 17:25:24 +0800
Subject: [PATCH] 更新代码

---
 src/main/java/com/webmanage/config/EncryptedPropertyEnvironmentPostProcessor.java        |   55 +++++++++++
 src/main/resources/META-INF/spring.factories                                             |    2 
 src/main/resources/application-dev.yml                                                   |    2 
 src/main/resources/application-prod.yml                                                  |   70 ++++++++++++++
 src/main/resources/META-INF/spring/org.springframework.boot.env.EnvironmentPostProcessor |    3 
 src/main/java/com/webmanage/config/EncryptedPropertyDetector.java                        |   24 ++++
 src/main/java/com/webmanage/util/AESUtil.java                                            |  136 +++++++++++++++++++++++++++
 7 files changed, 291 insertions(+), 1 deletions(-)

diff --git a/src/main/java/com/webmanage/config/EncryptedPropertyDetector.java b/src/main/java/com/webmanage/config/EncryptedPropertyDetector.java
new file mode 100644
index 0000000..782adea
--- /dev/null
+++ b/src/main/java/com/webmanage/config/EncryptedPropertyDetector.java
@@ -0,0 +1,24 @@
+package com.webmanage.config;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * 妫�娴嬮厤缃�兼槸鍚︿负鍔犲瘑鏍煎紡鐨勫伐鍏�
+ */
+public class EncryptedPropertyDetector {
+
+    private static final String PREFIX = "AES:";
+
+    public static boolean isEncrypted(String value) {
+        return StringUtils.hasText(value) && value.startsWith(PREFIX);
+    }
+
+    public static String stripPrefix(String value) {
+        if (!isEncrypted(value)) {
+            return value;
+        }
+        return value.substring(PREFIX.length());
+    }
+}
+
+
diff --git a/src/main/java/com/webmanage/config/EncryptedPropertyEnvironmentPostProcessor.java b/src/main/java/com/webmanage/config/EncryptedPropertyEnvironmentPostProcessor.java
new file mode 100644
index 0000000..6bb4d00
--- /dev/null
+++ b/src/main/java/com/webmanage/config/EncryptedPropertyEnvironmentPostProcessor.java
@@ -0,0 +1,55 @@
+package com.webmanage.config;
+
+import com.webmanage.util.AESUtil;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.EnumerablePropertySource;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.util.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 鍦ㄥ簲鐢ㄥ惎鍔ㄦ棭鏈熷鏁忔劅閰嶇疆杩涜瑙e瘑
+ */
+public class EncryptedPropertyEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
+
+    @Override
+    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+        Map<String, Object> overrides = new HashMap<>();
+        // 鎵弿鎵�鏈夊彲鏋氫妇灞炴�ф簮锛屾敹闆嗕互 AES: 寮�澶寸殑灞炴�у�煎苟瑙e瘑锛屾斁鍏ユ渶楂樹紭鍏堢骇瑕嗙洊婧�
+        for (org.springframework.core.env.PropertySource<?> ps : environment.getPropertySources()) {
+            if (ps instanceof EnumerablePropertySource) {
+                EnumerablePropertySource<?> eps = (EnumerablePropertySource<?>) ps;
+                for (String name : eps.getPropertyNames()) {
+                    Object raw = eps.getProperty(name);
+                    if (raw instanceof String) {
+                        String value = (String) raw;
+                        if (EncryptedPropertyDetector.isEncrypted(value)) {
+                            String cipher = EncryptedPropertyDetector.stripPrefix(value);
+                            String plain = AESUtil.decryptWithDefaultKey(cipher);
+                            overrides.put(name, plain);
+                        }
+                    }
+                }
+            }
+        }
+        if (!overrides.isEmpty()) {
+            MutablePropertySources sources = environment.getPropertySources();
+            sources.addFirst(new MapPropertySource("decryptedSensitiveProperties", overrides));
+        }
+    }
+
+    // 纭繚灏芥棭鎵ц
+    @Override
+    public int getOrder() {
+        // 鍦ㄩ厤缃枃浠跺姞杞藉畬鎴愬悗鎵ц锛岄伩鍏嶆嬁涓嶅埌鍊�
+        return Ordered.LOWEST_PRECEDENCE;
+    }
+}
+
+
diff --git a/src/main/java/com/webmanage/util/AESUtil.java b/src/main/java/com/webmanage/util/AESUtil.java
new file mode 100644
index 0000000..3bd38e4
--- /dev/null
+++ b/src/main/java/com/webmanage/util/AESUtil.java
@@ -0,0 +1,136 @@
+package com.webmanage.util;
+
+import com.webmanage.common.BusinessException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * AES鍔犲瘑宸ュ叿绫�
+ *
+ * @author August
+ * @date 2022-07-29
+ */
+@Slf4j
+public class AESUtil {
+
+    private AESUtil() {
+    }
+
+    /**
+     * AES_KEY
+     */
+    private static final String AES_KEY = "sD6i0YYW1a5FnzF6vRf13VtHocZabRcI";
+
+    /**
+     * GCM_IV
+     */
+    private static final String GCM_IV = "1SzB4YR0c0E9";
+
+    /**
+     * GCM_TAG闀垮害
+     */
+    private static final int GCM_TAG_LENGTH = 16;
+
+    /**
+     * 鍔犲瘑
+     *
+     * @param plaintext 寰呭姞瀵嗘枃鏈�
+     * @param key       AES_KEY
+     * @param iv        GCM_IV
+     * @return 瀵嗘枃
+     */
+    public static String encrypt(String plaintext, byte[] key, byte[] iv) {
+        if (StringUtils.isBlank(plaintext) || key == null || iv == null) {
+            throw new BusinessException("鍔犲瘑鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        try {
+            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+
+            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
+
+            cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
+
+            // Perform Encryption
+            byte[] cipherText = cipher.doFinal(plaintext.getBytes());
+            StringBuilder sb = new StringBuilder();
+            for (byte b : cipherText) {
+                String hex = Integer.toHexString(b & 0xFF);
+                if (hex.length() == 1) {
+                    hex = '0' + hex;
+                }
+                sb.append(hex);
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            throw new BusinessException("鍔犲瘑澶辫触");
+        }
+    }
+
+    /**
+     * 瑙e瘑
+     *
+     * @param cipherText 瀵嗘枃
+     * @param key        AES_KEY
+     * @param iv         GCM_IV
+     * @return 瑙e瘑缁撴灉
+     */
+    public static String decrypt(String cipherText, byte[] key, byte[] iv) {
+        if (StringUtils.isBlank(cipherText) || key == null || iv == null) {
+            throw new BusinessException("瑙e瘑鍙傛暟涓嶈兘涓虹┖");
+        }
+
+        try {
+            byte[] cipherTextByte = new byte[cipherText.length() / 2];
+            for (int i = 0; i < cipherText.length() / 2; i++) {
+                int high = Integer.parseInt(cipherText.substring(i * 2, i * 2 + 1),
+                        16);
+                int low = Integer.parseInt(
+                        cipherText.substring(i * 2 + 1, i * 2 + 2), 16);
+                cipherTextByte[i] = (byte) (high * 16 + low);
+            }
+
+            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+
+            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
+
+            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv);
+
+            cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
+
+            byte[] decryptedText = cipher.doFinal(cipherTextByte);
+
+            return new String(decryptedText);
+        } catch (Exception e) {
+            throw new BusinessException("瑙e瘑澶辫触");
+        }
+    }
+
+    /**
+     * 浣跨敤榛樿瀵嗛挜鍜孖V杩涜瑙e瘑
+     * @param cipherText 浠ュ崄鍏繘鍒跺瓧绗︿覆琛ㄧず鐨勫瘑鏂�
+     * @return 鏄庢枃
+     */
+    public static String decryptWithDefaultKey(String cipherText) {
+        return decrypt(cipherText, AES_KEY.getBytes(), GCM_IV.getBytes());
+    }
+
+    public static void main(String[] args) {
+        // String plainText = "zynlpt2024";
+        String plainText = "postgres";
+
+        log.info("Original Text : " + plainText);
+
+        String cipherText = encrypt(plainText, AES_KEY.getBytes(), GCM_IV.getBytes());
+        log.info("Encrypted Text : " + cipherText);
+
+        String decryptedText = decrypt(cipherText, AES_KEY.getBytes(), GCM_IV.getBytes());
+        log.info("DeCrypted Text : " + decryptedText);
+    }
+}
diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..af6e0fd
--- /dev/null
+++ b/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.env.EnvironmentPostProcessor=\
+com.webmanage.config.EncryptedPropertyEnvironmentPostProcessor
\ No newline at end of file
diff --git a/src/main/resources/META-INF/spring/org.springframework.boot.env.EnvironmentPostProcessor b/src/main/resources/META-INF/spring/org.springframework.boot.env.EnvironmentPostProcessor
new file mode 100644
index 0000000..595ecdd
--- /dev/null
+++ b/src/main/resources/META-INF/spring/org.springframework.boot.env.EnvironmentPostProcessor
@@ -0,0 +1,3 @@
+com.webmanage.config.EncryptedPropertyEnvironmentPostProcessor
+
+
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index effd90b..7981842 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -5,7 +5,7 @@
     driver-class-name: org.postgresql.Driver
     url: jdbc:postgresql://localhost:5432/web_manage?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
     username: postgres
-    password: zkyxpostgres
+    password: AES:d9d2d3e0d586e76d02a97c451f3256bffdc806b4c7626904
     druid:
       # 鍒濆杩炴帴鏁�
       initial-size: 5
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..7581c4d
--- /dev/null
+++ b/src/main/resources/application-prod.yml
@@ -0,0 +1,70 @@
+  # 鏁版嵁婧愰厤缃�
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: org.postgresql.Driver
+    url: jdbc:postgresql://192.168.20.52:5432/zypt-v2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+    username: postgres
+    password: AES:f9d2d3e0d586e76d14aba9d24666acef98c4605be9ec680ac4cbeede7ad2
+    druid:
+      # 鍒濆杩炴帴鏁�
+      initial-size: 5
+      # 鏈�灏忚繛鎺ユ睜鏁伴噺
+      min-idle: 10
+      # 鏈�澶ц繛鎺ユ睜鏁伴噺
+      max-active: 20
+      # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂�
+      max-wait: 60000
+      # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶆槸姣
+      time-between-eviction-runs-millis: 60000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      min-evictable-idle-time-millis: 300000
+      # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+      max-evictable-idle-time-millis: 900000
+      # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
+      validation-query: SELECT 1
+      test-while-idle: true
+      test-on-borrow: false
+      test-on-return: false
+      # 鎵撳紑PSCache锛屽苟涓旀寚瀹氭瘡涓繛鎺ヤ笂PSCache鐨勫ぇ灏�
+      pool-prepared-statements: true
+      max-pool-prepared-statement-per-connection-size: 20
+      # 閰嶇疆鐩戞帶缁熻鎷︽埅鐨刦ilters锛屽幓鎺夊悗鐩戞帶鐣岄潰sql鏃犳硶缁熻锛�'wall'鐢ㄤ簬闃茬伀澧�
+      filters: stat,wall,slf4j
+      # 閫氳繃connectProperties灞炴�ф潵鎵撳紑mergeSql鍔熻兘锛涙參SQL璁板綍
+      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
+      # 閰嶇疆DruidStatFilter
+      web-stat-filter:
+        enabled: true
+        url-pattern: /*
+        exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
+      # 閰嶇疆DruidStatViewServlet
+      stat-view-servlet:
+        enabled: true
+        url-pattern: /druid/*
+        reset-enable: false
+        login-username: admin
+        login-password: 123456
+
+  # Redis閰嶇疆
+  redis:
+    host: 192.168.20.51
+    port: 6379
+    password: AES:c8d9cdfddcb4b32c677d657d2c8d56f9e7e4720832656637f5
+    database: 4
+    timeout: 10000ms
+    lettuce:
+      pool:
+        max-active: 8
+        max-wait: -1ms
+        max-idle: 8
+        min-idle: 0
+# MinIO閰嶇疆
+minio:
+   endpoint: http://192.168.20.52:9000
+   access-key: minioadmin
+   secret-key: AES:c4d4cefddd95e6733df755af0e29839c104ee8baa55eb53cdc24
+   part-size: 104857600
+   bucket-name: dev
+
+

--
Gitblit v1.8.0