基于SpringBoot3+Java17+Nacos的配置中心和本地配置文件加解密

一、技术架构

1.1 核心依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2023.0.3.4</version>
</dependency>
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>

二、Nacos配置中心加解密

2.1 自定义StringEncryptor实现

java 复制代码
@Component("ymlDecryptConfig")
public class YmlDecryptConfig implements StringEncryptor {
    
    @Resource
    private Sm4EncryptUtils sm4EncryptUtils;

    @Override
    public String encrypt(String message) {
        return sm4EncryptUtils.encrypt(message);
    }

    @Override
    public String decrypt(String encryptedMessage) {
        return sm4EncryptUtils.decrypt(encryptedMessage);
    }
}

2.2 配置文件配置

yaml 复制代码
jasypt:
  encryptor:
    bean: ymlDecryptConfig

spring:
  cloud:
    nacos:
      config:
        username: ENC(加密字符串)
        password: ENC(加密字符串)

三、本地配置文件加解密实现

3.1 核心原理分析

BindHandler接口作用
java 复制代码
// Spring Boot 2.4+ 引入的配置绑定机制
public interface BindHandler {
    // 在绑定属性成功后调用,可以对结果进行处理
    Object onSuccess(ConfigurationPropertyName name, 
                     Bindable<?> target, 
                     BindContext context, 
                     Object result);
    
    // 绑定前、绑定失败等方法
    // ...
}
TextEncryptorBindHandler分析

在spring-cloud-context包中:

java 复制代码
// Spring Cloud 内置的解密处理器
public class TextEncryptorBindHandler extends AbstractBindHandler {
    
    @Override
    public Object onSuccess(ConfigurationPropertyName name, 
                           Bindable<?> target, 
                           BindContext context, 
                           Object result) {
        
        if (result instanceof String) {
            String value = (String) result;
            // 检查是否有加密前缀,如"ENC(...)"
            if (value.startsWith("ENC(") && value.endsWith(")")) {
                // 调用TextEncryptor进行解密
                return textEncryptor.decrypt(extractEncryptedValue(value));
            }
        }
        return result;
    }
}

3.2 自定义BindHandler实现

java 复制代码
public class CustomBindHandler extends AbstractBindHandler {
    
    private static final String ENV_KEY = "CONFIG_ENCRYPT_KEY";
    private static final String PREFIX = "ENC(";
    private static final String SUFFIX = ")";
    
    private final YmlDecryptConfig decryptConfig;
    
    public CustomBindHandler() {
        // 从环境变量获取密钥
        String key = System.getenv(ENV_KEY);
        if (key == null) {
            key = System.getProperty(ENV_KEY.toLowerCase().replace("_", "."));
        }
        
        // 创建解密器
        this.decryptConfig = createDecryptConfig(key);
    }
    
    @Override
    public Object onSuccess(ConfigurationPropertyName name, 
                           Bindable<?> target, 
                           BindContext context, 
                           Object result) {
        
        if (result instanceof String) {
            String value = (String) result;
            // 匹配ENC(...)格式
            if (value.startsWith(PREFIX) && value.endsWith(SUFFIX)) {
                // 提取并解密
                String encrypted = value.substring(PREFIX.length(), 
                                                  value.length() - SUFFIX.length());
                return decryptConfig.decrypt(encrypted);
            }
        }
        return result;
    }
    
    private YmlDecryptConfig createDecryptConfig(String key) {
        YmlDecryptConfig config = new YmlDecryptConfig();
        Sm4EncryptUtils utils = new Sm4EncryptUtils();
        utils.setPrivateKey(key);
        config.setSm4EncryptUtils(utils);
        return config;
    }
}

3.3 注册自定义处理器

java 复制代码
@Configuration
public class BootstrapConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public BindHandler bindHandler() {
        return new CustomBindHandler();
    }
}

在META-INF/spring.factories中:

properties 复制代码
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.example.config.BootstrapConfiguration

四、底层机制解析

4.1 配置加载流程

复制代码
1. SpringApplication启动
2. 加载bootstrap配置文件
3. PropertySourceLoader解析配置文件
4. Binder进行属性绑定
5. BindHandler链式处理
6. TextEncryptorBindHandler/CustomBindHandler解密
7. 将解密后的值注入Bean

4.2 BindHandler工作机制

java 复制代码
// Binder中的关键代码
public <T> T bindOrCreate(ConfigurationPropertyName name, Bindable<T> target,
        BindHandler handler) {
    
    // 创建绑定上下文
    BindContext context = new ApplicationBindContext();
    
    // 执行绑定
    return bind(name, target, handler, context, false);
}

private <T> T bind(ConfigurationPropertyName name, Bindable<T> target,
        BindHandler handler, BindContext context, boolean allowRecursiveBinding) {
    
    // 调用BindHandler的onStart方法
    handler.onStart(name, target, context);
    
    try {
        // 执行实际绑定
        T result = doBind(name, target, context, allowRecursiveBinding);
        
        // 调用onSuccess方法(解密在这里发生)
        result = handler.onSuccess(name, target, context, result);
        
        return result;
    } catch (Exception ex) {
        // 处理异常
        return handler.onFailure(name, target, context, ex);
    } finally {
        // 清理
        handler.onFinish(name, target, context);
    }
}

4.3 TextEncryptorBindHandler vs CustomBindHandler

特性 TextEncryptorBindHandler CustomBindHandler
解密时机 属性绑定成功后 属性绑定成功后
加密前缀 可配置 ENC(...)固定格式
加密算法 Jasypt默认 SM4国密算法
密钥来源 jasypt.encryptor.password 环境变量
集成方式 Spring Cloud内置 自定义实现

4.4 Spring Cloud 2023.0.3.4版本适配

java 复制代码
// 新版Spring Cloud中,TextEncryptorBindHandler已被重构
// 核心逻辑移动到PropertySourceBootstrapConfiguration中

public class PropertySourceBootstrapConfiguration 
        implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    
    @Override
    public void initialize(ConfigurableApplicationContext context) {
        // 加载PropertySource
        List<PropertySource<?>> sources = loadPropertySources();
        
        // 应用解密处理器
        for (PropertySource<?> source : sources) {
            if (source instanceof OriginTrackedMapPropertySource) {
                // 解密处理
                decryptPropertySource((OriginTrackedMapPropertySource) source);
            }
        }
    }
}

五、完整示例配置

5.1 bootstrap.yml

yaml 复制代码
spring:
  application:
    name: demo-service
  cloud:
    nacos:
      config:
        server-addr: ${NACOS_HOST:localhost}:8848
        username: ${NACOS_USER:ENC(加密用户名)}
        password: ${NACOS_PASS:ENC(加密密码)}
        
  datasource:
    url: jdbc:mysql://localhost:3306/demo
    username: ENC(加密用户名)
    password: ENC(加密密码)
    
  redis:
    password: ENC(加密Redis密码)

5.2 启动参数

bash 复制代码
# 设置加密密钥
export CONFIG_ENCRYPT_KEY=your-32bit-sm4-key

# 启动应用
java -jar app.jar \
  --spring.profiles.active=prod \
  --CONFIG.ENCRYPT.KEY=${CONFIG_ENCRYPT_KEY}

六、关键注意事项

  1. 密钥安全:生产环境密钥必须通过环境变量或密钥管理服务传入
  2. 加密格式 :必须使用ENC(加密内容)格式包裹
  3. 处理器顺序:确保CustomBindHandler在绑定链中的正确顺序
  4. 版本兼容:Spring Cloud 2023.0.3.4与Spring Boot 3.x的兼容性已验证
  5. 性能影响:加解密操作在启动时一次性完成,不影响运行时性能

七、总结

通过自定义StringEncryptor和BindHandler,实现了Nacos配置中心和本地配置文件的双重加密保护。关键点在于理解Spring Boot的配置绑定机制和Spring Cloud的解密处理流程,特别是BindHandler的onSuccess方法在属性绑定后的处理时机。

相关推荐
ScilogyHunter10 分钟前
Hercules系列安全MCU功能安全原理详解
java·单片机·安全·hercules
博风30 分钟前
eclipse中配置maven,以及在本地使用maven。
java·eclipse·maven
云-缩影30 分钟前
实际项目中怎么选排序算法:从面试题到工程落地
java·算法·排序算法
追星星の人32 分钟前
java web项目(eclipse软件)全流程备份
java·servlet
文丑颜不良啊1 小时前
LeetCode1461~1480题目解析
java·leetcode
2301_780789669 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
学长毕设10 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
步行cgn10 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川10 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵11 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程