refactor: 配置刷新优化和加密功能移除

- refactor(springboot2): 简化配置刷新逻辑,移除 EnvironmentChangeEvent 包装
  - ConfigChangeHanlder 直接接收 Map<String,String> 参数
  - 移除 EnvironmentChangeEvent 事件类
  - 优化 token 参数构建和敏感信息脱敏处理
- refactor(server): 移除配置加密功能
  - 删除 CryptoConfig 结构体和相关配置项
  - 移除 application-dev.properties 中的加密配置
  - 项目不再使用配置加密功能
- docs: 更新 README 和模块文档
- fix: 修复 Node.js 客户端配置缓存
This commit is contained in:
2026-03-25 21:00:59 +08:00
parent c2e599097e
commit 751a0f770f
6 changed files with 448 additions and 571 deletions
-1
View File
@@ -64,7 +64,6 @@ database.user=root
database.password=your_password database.password=your_password
jwt.secret=your-jwt-secret jwt.secret=your-jwt-secret
jwt.expireHours=24 jwt.expireHours=24
crypto.secretKey=your-crypto-key
``` ```
启动服务(首次启动自动建表并初始化默认数据): 启动服务(首次启动自动建表并初始化默认数据):
@@ -1,5 +1,4 @@
{ {
"crypto.secretKey": "k9#mP2$vL7qR4xN8",
"database.host": "127.0.0.1", "database.host": "127.0.0.1",
"database.name": "kenaito_conf", "database.name": "kenaito_conf",
"database.password": "1234567", "database.password": "1234567",
@@ -4,5 +4,5 @@ import java.util.Map;
public interface ConfigChangeHanlder { public interface ConfigChangeHanlder {
public void onConfigChanged(Map<String, Object> changedConfigs); void onConfigChanged(Map<String, Object> changedConfigs);
} }
@@ -7,12 +7,6 @@ import java.security.MessageDigest;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -141,67 +135,6 @@ public class ConfigcenterContext {
return null; return null;
} }
// ==================== Crypto Utils (replaces mendmix AES/DES/Base64/DigestUtils) ====================
public static String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
throw new RuntimeException("MD5 error", e);
}
}
public static String md5Short(String input) {
if (input == null || input.isEmpty()) return "";
return md5(input).substring(0, 16);
}
private static String desEncrypt(String key, String data) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "DES");
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("DES encrypt error", e);
}
}
private static byte[] aesDecrypt(byte[] data, byte[] key) throws Exception {
SecretKey secretKey = new SecretKeySpec(key, "AES");
// Use CBC mode with zero IV to match Go server
IvParameterSpec iv = new IvParameterSpec(new byte[16]);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] decrypted = cipher.doFinal(data);
// Remove PKCS7 padding
int padding = decrypted[decrypted.length - 1] & 0xFF;
if (padding > 0 && padding <= 16) {
byte[] result = new byte[decrypted.length - padding];
System.arraycopy(decrypted, 0, result, 0, result.length);
return result;
}
return decrypted;
}
private static String decryptWithAES(String key, String data) {
try {
String secretKey = md5(key).substring(16);
byte[] encrypted = Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8));
byte[] decrypted = aesDecrypt(encrypted, secretKey.getBytes(StandardCharsets.UTF_8));
return new String(decrypted, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(String.format("解密错误:%s", data));
}
}
// ==================== HTTP Utils (replaces mendmix HttpUtils) ==================== // ==================== HTTP Utils (replaces mendmix HttpUtils) ====================
public static String httpGet(String url) throws Exception { public static String httpGet(String url) throws Exception {
@@ -242,8 +175,7 @@ public class ConfigcenterContext {
syncIntervalSeconds = getInt("kenaito.config.sync-interval-seconds", 60); syncIntervalSeconds = getInt("kenaito.config.sync-interval-seconds", 60);
token = getProperty("kenaito.config.token"); token = getProperty("kenaito.config.token");
logger.info("\n=====Configcenter config=====\nappName:{}\nenv:{}\nversion:{}\nremoteEnabled:{}\napiBaseUrls:{}\n=====Configcenter config=====", logger.info("\n=====Configcenter config=====\nappName:{}\nenv:{}\nversion:{}\nremoteEnabled:{}\napiBaseUrls:{}\n=====Configcenter config=====", app, env, version, isRemoteEnabled(), JSON.toJSONString(apiBaseUrls));
app, env, version, isRemoteEnabled(), JSON.toJSONString(apiBaseUrls));
} }
public boolean isRemoteEnabled() { public boolean isRemoteEnabled() {
@@ -271,15 +203,29 @@ public class ConfigcenterContext {
} }
} }
public String getApp() { return app; } public String getApp() {
public String getEnv() { return env; } return app;
public String getVersion() { return version; } }
public boolean isIgnoreGlobal() { return ignoreGlobal; }
public String getSecret() { return secret; } public String getEnv() {
public boolean isRemoteFirst() { return remoteFirst; } return env;
public int getSyncIntervalSeconds() { return syncIntervalSeconds; } }
public String getNodeId() { return nodeId; }
public boolean isSpringboot() { return isSpringboot; } public String getVersion() {
return version;
}
public boolean isIgnoreGlobal() {
return ignoreGlobal;
}
public boolean isRemoteFirst() {
return remoteFirst;
}
public int getSyncIntervalSeconds() {
return syncIntervalSeconds;
}
public void mergeRemoteProperties(Properties properties) { public void mergeRemoteProperties(Properties properties) {
if (!remoteEnabled) return; if (!remoteEnabled) return;
@@ -343,7 +289,7 @@ public class ConfigcenterContext {
Set<String> keys = map.keySet(); Set<String> keys = map.keySet();
for (String key : keys) { for (String key : keys) {
Object value = decodeEncryptIfRequire(map.get(key)); Object value = map.get(key);
properties.put(key, value); properties.put(key, value);
} }
@@ -412,7 +358,7 @@ public class ConfigcenterContext {
Set<String> keySet = updateConfig.keySet(); Set<String> keySet = updateConfig.keySet();
for (String key : keySet) { for (String key : keySet) {
String oldValue = getProperty(key); String oldValue = getProperty(key);
addProperty(key, decodeEncryptIfRequire(updateConfig.get(key)).toString()); addProperty(key, updateConfig.get(key).toString());
logger.info("Config [{}] Change, oldValue:{}, newValue:{}", key, oldValue, updateConfig.get(key)); logger.info("Config [{}] Change, oldValue:{}, newValue:{}", key, oldValue, updateConfig.get(key));
} }
@@ -494,8 +440,7 @@ public class ConfigcenterContext {
// 刷新 // 刷新
registry.refresh(); registry.refresh();
logger.info("[RefreshScope] RefreshScopeRegistry.refresh() completed, refreshed {} @Value fields and {} @ConfigurationProperties beans", logger.info("[RefreshScope] RefreshScopeRegistry.refresh() completed, refreshed {} @Value fields and {} @ConfigurationProperties beans", registry.getValueFieldCount(), registry.getConfigPropsCount());
registry.getValueFieldCount(), registry.getConfigPropsCount());
} catch (Exception e) { } catch (Exception e) {
logger.warn("[RefreshScope] RefreshScopeRegistry.refresh() error, msg:{}", e.getMessage(), e); logger.warn("[RefreshScope] RefreshScopeRegistry.refresh() error, msg:{}", e.getMessage(), e);
} }
@@ -504,21 +449,6 @@ public class ConfigcenterContext {
} }
} }
public boolean pingCcServer(String pingUrl, int retry) {
boolean result = false;
try {
result = httpGet(pingUrl) != null;
} catch (Exception e) {
// ignore
}
if (retry == 0) return false;
if (!result) {
try { Thread.sleep(1500); } catch (Exception e) { }
return pingCcServer(pingUrl, --retry);
}
return result;
}
public String buildTokenParameter(String url) { public String buildTokenParameter(String url) {
if (token == null || token.isEmpty()) { if (token == null || token.isEmpty()) {
return url; return url;
@@ -532,26 +462,6 @@ public class ConfigcenterContext {
} }
} }
private Object decodeEncryptIfRequire(Object data) {
if (data == null) return "";
if (data.toString().startsWith(CRYPT_PREFIX)) {
Validate.notBlank(secret, "config[kenaito.config.encrypt-secret] is required");
data = data.toString().replace(CRYPT_PREFIX, "");
String decryptString;
try {
decryptString = decryptWithAES(secret, data.toString());
} catch (Exception e) {
if (globalSecret != null && !globalSecret.isEmpty()) {
decryptString = decryptWithAES(globalSecret, data.toString());
} else {
throw e;
}
}
return decryptString;
}
return data;
}
private String hideSensitive(String key, String origin) { private String hideSensitive(String key, String origin) {
if (StringUtils.isAnyBlank(key, origin)) return ""; if (StringUtils.isAnyBlank(key, origin)) return "";
boolean isSensitive = false; boolean isSensitive = false;
@@ -1,24 +0,0 @@
package cn.odboy.confcenter;
import java.util.Set;
import org.springframework.context.ApplicationEvent;
public class EnvironmentChangeEvent extends ApplicationEvent {
private static final long serialVersionUID = 1L;
private Set<String> keys;
public EnvironmentChangeEvent(Set<String> keys) {
super(keys);
this.keys = keys;
}
/**
* @return the keys
*/
public Set<String> getKeys() {
return keys;
}
}
-7
View File
@@ -14,7 +14,6 @@ type Config struct {
Server ServerConfig Server ServerConfig
Database DatabaseConfig Database DatabaseConfig
JWT JWTConfig JWT JWTConfig
Crypto CryptoConfig
} }
type ServerConfig struct { type ServerConfig struct {
@@ -35,10 +34,6 @@ type JWTConfig struct {
ExpireHours int ExpireHours int
} }
type CryptoConfig struct {
SecretKey string
}
var Cfg *Config var Cfg *Config
func Load(path string) error { func Load(path string) error {
@@ -77,8 +72,6 @@ func Load(path string) error {
Cfg.JWT.Secret = baseProps["jwt.secret"] Cfg.JWT.Secret = baseProps["jwt.secret"]
Cfg.JWT.ExpireHours = intProp(baseProps, "jwt.expireHours", 24) Cfg.JWT.ExpireHours = intProp(baseProps, "jwt.expireHours", 24)
Cfg.Crypto.SecretKey = baseProps["crypto.secretKey"]
if Cfg.Database.Host == "" { if Cfg.Database.Host == "" {
return fmt.Errorf("missing required config: database.host") return fmt.Errorf("missing required config: database.host")
} }