Druid实现数据源加密(单数据源与多数据源类似)

阿里的Druid数据库连接池其实是支持用户名密码做加密处理的,有对应的callback配置,

官网中有相应介绍,详见:https://github.com/alibaba/druid/wiki/DruidDataSource配置属性列表

官网中只介绍了密码加密,根据源码发现用户名也是支持加密的,只是文档没有及时更新。

源码获取连接信息处理逻辑:

 因此,可在项目中添加以下配置及对应的callBack处理类:

1、添加连接参数配置:

<!-- 密码解密处理类 -->
<bean id="dbPasswordCallback" class="com.simple.test.DbPasswordCallback">
<property name="encPassword" value="#{app['jdbc.password']}" />
</bean>
<!--用户名解密处理类 -->
<bean id="dbNameCallback" class="com.simple.test.DbNameCallback">
<constructor-arg index="0" value="123123123" />
    <property name="encUserName" value="#{app['jdbc.username']}" />
</bean>
<!-- 数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="#{app['jdbc.url']}" />
        <property name="username" value="#{app['jdbc.username']}" />
        <property name="password" value="#{app['jdbc.password']}" />
        <property name="filters" value="slf4j" />
        <property name="maxActive" value="#{app['jdbc.maxActive']}" />
        <property name="initialSize" value="#{app['jdbc.initialSize']}" />
        <property name="minIdle" value="#{app['jdbc.minIdle']}" />
        <!-- 配置获取连接等待超时的时间 -->
        <property name="maxWait" value="#{app['jdbc.maxWait']}" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="validationQuery" value="SELECT 'x'" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <!-- 通过connectProperties参数配置加密密钥 -->
        <property name="connectProperties">
            <props>
                <prop key="appPrivateKeyFilePath">123123123</prop>
            </props>
        </property>
        <!-- 配置用户名、密码解密处理类 -->
        <property name="userCallback" ref="dbNameCallback" />
        <property name="passwordCallback" ref="dbPasswordCallback" />
    </bean>

2、添加相应的依赖

本帖使用的Jasypt加密,可以使用其他的加密算法,如AES等等。

<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.3</version>
</dependency>

3、添加相应的解密处理类

/**
 * 用户名解密处理
 */
public class DbNameCallback extends NameCallback {

    private static final Logger logger = LoggerFactory.getLogger(DbNameCallback.class);

    private String encUserName;

    public DbNameCallback(String prompt) {
        super(prompt);
    }

    public DbNameCallback(String prompt, String defaultName) {
        super(prompt, defaultName);
    }

    public String getEncUserName() {
        return encUserName;
    }

    public void setEncUserName(String encUserName) {
        this.encUserName = encUserName;
    }

    @Override
    public String getName() {
        // 获取配置参数中的密钥
        String propertyPwd = getPrompt();
        try {
            StandardPBEStringEncryptor decryptor = new StandardPBEStringEncryptor();
            decryptor.setAlgorithm("PBEWithMD5AndDES");
            decryptor.setPassword(propertyPwd);
            encUserName = encUserName.substring(4, encUserName.length()-1);
            return decryptor.decrypt(encUserName);
        } catch (Exception e) {
            logger.error("Druid ConfigTools.decrypt", e);
        }
        return "";
    }
}
/**
 * 密码解密处理类
 */
public class DbPasswordCallback  extends DruidPasswordCallback {

    private static final Logger logger = LoggerFactory.getLogger(DbPasswordCallback.class);

    private String encPassword;

    public String getEncPassword() {
        return encPassword;
    }

    public void setEncPassword(String encPassword) {
        this.encPassword = encPassword;
    }

    @Override
    public void setProperties(Properties properties){
        super.setProperties(properties);
        // 获取配置参数中的密钥
        String propertyPwd = properties.getProperty("appPrivateKeyFilePath");
        try {
            StandardPBEStringEncryptor decryptor = new StandardPBEStringEncryptor();
            decryptor.setAlgorithm("PBEWithMD5AndDES");
            decryptor.setPassword(propertyPwd);
            encPassword = StringUtils.subString(encPassword, "ENC(", ")");
            String decryptedText = decryptor.decrypt(encPassword);
            //String dbpassword = ConfigTools.decrypt(publickey, encryptionPassword);
            setPassword(decryptedText.toCharArray());
        } catch (Exception e) {
            logger.error("Druid ConfigTools.decrypt", e);
        }
    }
}

4、以下是本地生成加密串的方法,无需提交

public static void main(String[] args) {
// 注意:加密密钥必须与生产环境一致
    String encryptionPassword = "123123123";
    StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
    encryptor.setAlgorithm("PBEWithMD5AndDES");
    encryptor.setPassword(encryptionPassword);
    String plainText = "test_name";
    String encryptedText = encryptor.encrypt(plainText);
    System.out.println("加密后的文本: ENC(" + encryptedText + ")");

    StandardPBEStringEncryptor decryptor = new StandardPBEStringEncryptor();
    decryptor.setAlgorithm("PBEWithMD5AndDES");
    decryptor.setPassword(encryptionPassword);
    String decryptedText = decryptor.decrypt(encryptedText);
    System.out.println("解密后的文本: " + decryptedText);
}

至此,完美解决。

posted @ 2025-07-15 14:29  Commissar-Xia  阅读(104)  评论(0)    收藏  举报