在日常开发中连接数据库是必然的,开发和测试环境数据库使用敏文密码还好,生产如果采用明文配置讲会有安全问题,jasypt是一个通用的加解密库,我们可以使用他来进行对数据库的加密操作。

第一种方式

一下这种方式只针对于使用Druid连接池的项目。

pom

<dependency>
      <groupId>com.github.ulisesbocchio</groupId>
      <artifactId>jasypt-spring-boot-starter</artifactId>
      <version>3.0.2</version>
</dependency>

Main

public static void main(String[] args) {
    BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
    // 加密所需的salt(盐)
    textEncryptor.setPassword("");
    // 要加密的数据(数据库的用户名或密码)
    String password = textEncryptor.encrypt("");
    System.out.println("password:" + password);
}

运行以后把加密之后的密码放入yml配置文件中。

修改数据源

加密需要使用到盐值,所以我们这里配置通过启动参数来进行传递。

自定义类-SyncDataSource

SyncDataSource继承com.alibaba.druid.pool.DruidDataSource重写getPassword方法。

public class SyncDataSource extends DruidDataSource {

    private static String key = "";

    public SyncDataSource() {
    }

    /**
     * 如果有多个数据库可以传递一个type类型来区分盐值
     *
     * @param publicKey
     */
    public SyncDataSource(String publicKey) {
        key = publicKey;
    }

    @Override
    public String getPassword() {
        // 获取密码
        String encPassword = super.getPassword();
        // 解密密码
        BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
        textEncryptor.setPassword(key);
        String decrypt = textEncryptor.decrypt(encPassword);
        return decrypt;
    }
}

第二种方式

第一种方式可以实现数据库加密操作,但是如果项目引入了redis,阿里云oss等,用上面的方式就有一些麻烦了,这里我们就用第二种方式,在项目启动时获取yml里面的所有参数,然后进行解密操作。

pom

<dependency>
      <groupId>com.github.ulisesbocchio</groupId>
      <artifactId>jasypt-spring-boot-starter</artifactId>
      <version>3.0.2</version>
</dependency>

Main

public static void main(String[] args) {
    BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
    // 加密所需的salt(盐)
    textEncryptor.setPassword("");
    // 要加密的数据(数据库的用户名或密码)
    String password = textEncryptor.encrypt("");
    System.out.println("password:" + password);
}

以上的步骤还是和之前的一样,只不过参数不一样了。

获取并代理配置文件-ResourcePlaceholderConfig

import com.xffjs.framework.config.properties.EncryptPropertyPlaceholderConfigurer;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;

import java.util.Properties;

/**
 * @className: ResourcePlaceholderConfig
 * @description: 获取配置文件
 * @author: xiaofei
 */
@Configuration
public class ResourcePlaceholderConfig {

    @Bean
    public PropertySourcesPlaceholderConfigurer propertyConfigurer() {
        PropertySourcesPlaceholderConfigurer config = new EncryptPropertyPlaceholderConfigurer();
        // 获取当前所激活的配置文件
        YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new ClassPathResource("application.yml"));
        Properties properties = yaml.getObject();
        String active = properties.getProperty("spring.profiles.active");
        // 读取当前所激活的配置文件
        yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new ClassPathResource("application-" + active + ".yml"));
        config.setProperties(yaml.getObject());
        return config;
    }
}

配置文件解密-EncryptPropertyPlaceholderConfigurer

import org.apache.commons.lang3.StringUtils;
import org.jasypt.util.text.BasicTextEncryptor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;

import java.util.Map;
import java.util.Properties;

/**
 * @className: EncryptPropertyPlaceholderConfigurer
 * @description: 配置文件解密
 * @author: xiaofei
 * @create: 2020年12月21日
 */
public class EncryptPropertyPlaceholderConfigurer extends PropertySourcesPlaceholderConfigurer implements InitializingBean {

    /**
     * 需要解密的配置项前缀
     */
    private static final String PREFIX_ENC = "enc:";


    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    protected Properties mergeProperties() {
        Properties mergedProperties = new Properties();
        for (Properties localProp : localProperties) {
            mergedProperties.putAll(localProp);
        }
        for (Map.Entry entry : mergedProperties.entrySet()) {
            if (entry.getValue().toString().startsWith(PREFIX_ENC)) {
                System.out.println("需要解密的key:" + entry.getValue().toString());
                String key = System.getProperty("salt");
                BasicTextEncryptor textEncryptor = new BasicTextEncryptor();
                textEncryptor.setPassword(key);
                String value = entry.getValue().toString().replace(PREFIX_ENC, StringUtils.EMPTY);
                String decrypt = textEncryptor.decrypt(value);
                mergedProperties.setProperty(entry.getKey().toString(), decrypt);
            }
        }
        MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
        sources.addFirst(new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergedProperties));
        return mergedProperties;
    }

    @Override
    public void afterPropertiesSet() {
        localOverride = true;
    }
}

盐值(salt)的配置

Idea配置:

一定要加-D,不然无法读取。

Jar启动配置:

一定放到前面,放到后面则不生效。

java -Dsalt=aaaa -jar XFBlog_prod.jar