springboot结合Druid加密数据库密码遇到的坑!

遇到的问题:程序运行时,连接数据库报错,如下图,


错误信息意思是访问被拒,先追踪报错信息到DruidDataSource.java这个类的init()这个方法的870行,如下图,


也就是说,在这个try的方法块里抛出了异常,开始从859行断点,进入createPhysicalConnection()方法,


调到这里,瞬间就明白了,密码是未解密的密文,当然连不上数据库了。顺着往下调,刚好找到了解决问题的办法,


Druid可以配置一个叫做passwordCallBack的参数,这个参数的值是一个全限定类名,这个类需要继承DruidPasswordCallback.java类,实现一个setProperties()方法,在这个方法里,可以将加密的密码通过Druid提供的ConfigTools.decrypt(publickey, password)方法进行解密,再通过DruidPasswordCallback.java类的父类PasswordCallback.java的setPassword()的方法赋值解密后的密码,再看上面图中1545行代码,password获得的值就是解密后的密码,请求连接数据库就没问题了。


整个问题处理的思路整理完了,下面把关键代码奉上。

import com.alibaba.druid.filter.config.ConfigTools;
import com.alibaba.druid.util.DruidPasswordCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Properties;

public class DbPasswordCallback extends DruidPasswordCallback {

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

    @Override
    public void setProperties(Properties properties) {
        super.setProperties(properties);
        String password = (String) properties.get("password");
        String publickey = (String) properties.get("publickey");
        try {
            String dbpassword = ConfigTools.decrypt(publickey, password);
            setPassword(dbpassword.toCharArray());
        } catch (Exception e) {
            LOGGER.error("Druid ConfigTools.decrypt", e);
        }
    }
}

这个是密码回调类,主要处理解密逻辑。

import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.sql.SQLException;

@Configuration
@MapperScan(basePackages = DbConfig.PACKAGE, sqlSessionFactoryRef = "sqlSessionFactory")
public class DbConfig {
    private static final Logger LOGGER = LoggerFactory.getLogger(DbConfig.class);
    static final String PACKAGE = "com.xxx.xx.dao";
    private static final String MAPPER_LOCATION = "classpath*:mapper/*.xml";
    private static final String DOMAIN_PACKAGE = "com.xxx.xx.dao.pojo";

    @Value("${spring.datasource.druid.url}")
    private String dbUrl;

    @Value("${spring.datasource.druid.username}")
    private String username;

    @Value("${spring.datasource.druid.password}")
    private String password;

    @Value("${spring.datasource.druid.driver-class-name}")
    private String driverClassName;

    @Value("${spring.datasource.type}")
    private String dbType;

    @Value("${spring.datasource.druid.initial-size}")
    private int initialSize;

    @Value("${spring.datasource.druid.min-idle}")
    private int minIdle;

    @Value("${spring.datasource.druid.max-active}")
    private int maxActive;

    @Value("${spring.datasource.druid.max-wait}")
    private int maxWait;

    @Value("${spring.datasource.druid.time-between-eviction-runs-millis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.druid.min-evictable-idle-time-millis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.validation-query}")
    private String validationQuery;

    @Value("${spring.datasource.druid.test-while-idle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.druid.test-on-borrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.druid.test-on-return}")
    private boolean testOnReturn;

    @Value("${spring.datasource.druid.pool-prepared-statements}")
    private boolean poolPreparedStatements;

    @Value("${spring.datasource.druid.max-pool-prepared-statement-per-connection-size}")
    private int maxPoolPreparedStatementPerConnectionSize;

    @Value("${spring.datasource.druid.filters}")
    private String filters;

    @Value("${spring.datasource.druid.connection-properties}")
    private String connectionProperties;

    @Value("${spring.datasource.druid.password-callback}")
    private String passwordCallbackClassName;

    @Bean(name = "dataSource")
    @Primary
    public DataSource dataSource() {
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);
        datasource.setInitialSize(initialSize);
        datasource.setMinIdle(minIdle);
        datasource.setMaxActive(maxActive);
        datasource.setMaxWait(maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setValidationQuery(validationQuery);
        datasource.setTestWhileIdle(testWhileIdle);
        datasource.setTestOnBorrow(testOnBorrow);
        datasource.setTestOnReturn(testOnReturn);
        datasource.setPoolPreparedStatements(poolPreparedStatements);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        datasource.setConnectionProperties(connectionProperties);
        datasource.setDbType(dbType);
        try {
            datasource.setPasswordCallbackClassName(passwordCallbackClassName);
        } catch (Exception e) {
            LOGGER.error("druid configuration initialization passwordCallbackClassName", e);
        }
        try {
            datasource.setFilters(filters);
        } catch (SQLException e) {
            LOGGER.error("druid configuration initialization filter", e);
        }
        return datasource;
    }

    @Bean(name = "transactionManager")
    @Primary
    public DataSourceTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    @Bean(name = "sqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(DbConfig.MAPPER_LOCATION));
        sessionFactory.setTypeAliasesPackage(DOMAIN_PACKAGE);
        sessionFactory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        return sessionFactory.getObject();
    }
}

这个是springboot配置Druid时需要显式注入一下数据源配置。

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=
spring.datasource.username=
spring.datasource.password=
spring.datasource.druid.url=
spring.datasource.druid.username=
spring.datasource.druid.password=
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.initial-size=1
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=1
spring.datasource.druid.max-wait=60000
spring.datasource.druid.pool-prepared-statements=false
spring.datasource.druid.max-pool-prepared-statement-per-connection-size=20
spring.datasource.druid.validation-query=SELECT 'x'
spring.datasource.druid.test-on-borrow=false
spring.datasource.druid.test-on-return=false
spring.datasource.druid.test-while-idle=true
spring.datasource.druid.time-between-eviction-runs-millis=60000
spring.datasource.druid.min-evictable-idle-time-millis=300000
spring.datasource.druid.filters=stat
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.password-callback=com.xxx.xx.dao.util.DbPasswordCallback
spring.datasource.publicKey=
spring.datasource.druid.connection-properties=config.decrypt=true;publickey=${spring.datasource.publicKey};password=${spring.datasource.druid.password}

这个是springboot的application.properties配置文件。


摁,就这么多。

猜你喜欢

转载自blog.csdn.net/ooobama/article/details/80752223