乐趣区

关于后端:SpringBoot-配置文件这样加密才足够安全

  1. 前景
    在应用 Springboot 时,通常很多信息都是在 application.yml 中间接明文配置的,比方数据库链接信息,redis 链接信息等等。然而这样是不平安的。
    所以须要对敏感数据进行加密,这样避免明码泄露
    Jasypt 这个库为咱们解决了这个问题,实现了 springboot 配置的自定加密加密
  2. 简略应用
    源码对应地址:

gitlab.sea-clouds.cn/csdn/spring…

2.1 引入依赖
<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.4.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <!– web 和 测试 –>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
    <!– jdbc –>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <!– jasypt 加密 –>
    <dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>
复制代码
2.2 配置 application 信息
jasypt 配置
jasypt:
  encryptor:
    # 加密算法
    algorithm: PBEWITHHMACSHA512ANDAES_256
    # 加密应用的盐
    password: jaspyt_password
复制代码
2.3 加密解密测试
/**
 * @author HLH
 * @description: 加密解密测试
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class JasyptTest {

    @Autowired
    private StringEncryptor stringEncryptor;

    /**
     * 加密解密测试
     */
    @Test
    public void jasyptTest() {
        // 加密
        System.out.println(stringEncryptor.encrypt(“root”));    // JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
        // 解密
        System.out.println(stringEncryptor.decrypt(“JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg”));    // root
    }

    /**
     * 手动测试
     */
    @Test
    public void test() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
        SimpleStringPBEConfig config = new SimpleStringPBEConfig();
        config.setPassword(“jaspyt_password”);
        config.setAlgorithm(“PBEWITHHMACSHA512ANDAES_256”);
        config.setKeyObtentionIterations(“1000”);
        config.setPoolSize(“1”);
        config.setProviderName(“SunJCE”);
        config.setSaltGeneratorClassName(“org.jasypt.salt.RandomSaltGenerator”);
        config.setIvGeneratorClassName(“org.jasypt.iv.RandomIvGenerator”);
        config.setStringOutputType(“base64”);
        encryptor.setConfig(config);
        System.out.println(encryptor.encrypt(“root”));    // JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
    }

}
复制代码

  1. 应用 Jasypt 加密后的字符串代替数据库明码
    3.1 应用加密类进行加密
    明码 root 加密之后 XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
    /**
     * 数据库明码加密
     */
    @Test
    public void encryptPasswored() {
        // 加密
        System.out.println(stringEncryptor.encrypt(“root”));    // XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1
        // 解密
        System.out.println(stringEncryptor.decrypt(“XjYnpGd3JGICnxumpFcfRP8J83m265yC/r1FiwLr9Yo1PNbPXQ2xykLHPpy02CZ1”));    // root
    }
    复制代码
    3.2 替换数据库配置
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.10.31/mp
        username: root
        # 应用 ENC() 包裹,标识为加密之后的,否则无奈解密,会报错
        password: ENC(R2H69h1aEgJ3EDPLXAVQ5CxZJWtl8EvqIJUtlATRt6om4w46/J+blu2JAvkR7Yvp)
    复制代码
    3.3 测试
    @Autowired
    private DataSource dataSource;
    /**
     * 测试加密之后的数据源应用是否失常
     *  查看是否能失常获取链接
     */
    @Test
    public void datasourceTest() throws SQLException {
        Connection connection = dataSource.getConnection();
        System.out.println(connection);     // HikariProxyConnection@1487059223 wrapping com.mysql.cj.jdbc.ConnectionImpl@48904d5a
        connection.close();
    }
    复制代码
  2. Jasypt 配置详解
    所有配置都在 JasyptEncryptorConfigurationProperties 类中定义,咱们只须要在 yml 中配置属性,即可达到重写的目标
    Jasypt 应用 StringEncryptor 来解密属性。如果 Spring 上下文中找不到自定义的 StringEncryptor,就会主动创立一个,能够通过以下属性进行配置
    惟一须要的属性是加密的盐,其余的能够应用默认值。尽管所有这些属性都能够在属性文件中生命,但加密所应用的盐不应该存储在属性文件中,而是应该通过零碎属性、命令行参数或者环境变量传递,只有他的名称是 jasypt.encryptor.password,它就能够工作。
    倒数第二个属性 jasypt.encryptor.proxyPropertySources 用于只是 jasypt spring boot 如何拦挡属性值进行解密。默认值 false 应用 PropertySource、EnumerablePropertySource 和 MapPropertySource 的自定义包装器实现。当为 true 时,拦挡机制将在每个特定的 PropertySource 实现上应用 CGLib 代理。在某些必须保留原始 PropertySource 类型的场景中,这可能很有用。
  3. 自定义加密
    默认状况下,bean 容器会配置 LazyJasyptSringEncryptor
    5.1 官网配置
    官网配置的 Bean 都是在 EncryptablePropertyResolverConfiguration 中进行注入的
    @Bean(
        name = {“lazyJasyptStringEncryptor”}
    )
    public StringEncryptor stringEncryptor(EnvCopy envCopy, BeanFactory bf) {
        String customEncryptorBeanName = envCopy.get().resolveRequiredPlaceholders(ENCRYPTOR_BEAN_PLACEHOLDER);
        boolean isCustom = envCopy.get().containsProperty(“jasypt.encryptor.bean”);
        return new DefaultLazyEncryptor(envCopy.get(), customEncryptorBeanName, isCustom, bf);
    }
    复制代码
    5.2 自定义加密
    能够在 Spring 上下文中共自定义本人的 StringEncryptor Bean,默认的加密程序将被疏忽
    留神

自定义 Bean 的名称必须为 jasyptStringEncryptor,否则解密不失效

自定义注入 bean
/**
 * 退出 StringEncryptor 加密解密类
 *      beanName 必须为 jasyptStringEncryptor 能力是自定义的失效
 *      configProps 为 jasypt 框架中读取的配置类,就不必本人读取了
 */
@Bean(“jasyptStringEncryptor”)
public StringEncryptor jasyptStringEncryptor(Singleton<JasyptEncryptorConfigurationProperties> configProps) {
    PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
    JasyptEncryptorConfigurationProperties jasyptProperties = configProps.get();
    SimpleStringPBEConfig config = new SimpleStringPBEConfig();
    config.setPassword(jasyptProperties.getPassword());
    config.setAlgorithm(jasyptProperties.getAlgorithm());
    config.setKeyObtentionIterations(jasyptProperties.getKeyObtentionIterations());
    config.setPoolSize(jasyptProperties.getPoolSize());
    config.setProviderName(jasyptProperties.getProviderName());
    config.setSaltGeneratorClassName(jasyptProperties.getSaltGeneratorClassname());
    config.setIvGeneratorClassName(jasyptProperties.getIvGeneratorClassname());
    config.setStringOutputType(jasyptProperties.getStringOutputType());
    encryptor.setConfig(config);
    return encryptor;
}
复制代码

  1. 自定义属性探测器
    属性探测器为判断一个属性值是否为加密后的字符串,并且截取实在字符串
    6.1 官网解决流程
    6.1.2 注入
    在 EncryptablePropertyResolverConfiguration 类中
    @Bean(
        name = {“lazyEncryptablePropertyDetector”}
    )
    public EncryptablePropertyDetector encryptablePropertyDetector(EnvCopy envCopy, BeanFactory bf) {
        String customDetectorBeanName = envCopy.get().resolveRequiredPlaceholders(DETECTOR_BEAN_PLACEHOLDER);
        boolean isCustom = envCopy.get().containsProperty(“jasypt.encryptor.property.detector-bean”);
        return new DefaultLazyPropertyDetector(envCopy.get(), customDetectorBeanName, isCustom, bf);
    }
    复制代码
    6.1.2 DefaultLazyPropertyDetector
    默认实现是 DefaultLazyPropertyDetector,具体代码是
    @Slf4j
    public class DefaultLazyPropertyDetector implements EncryptablePropertyDetector {

    // 属性探测器
    private Singleton<EncryptablePropertyDetector> singleton;

    public DefaultLazyPropertyDetector(ConfigurableEnvironment environment, String customDetectorBeanName, boolean isCustom, BeanFactory bf) {
        singleton = new Singleton<>(() ->
                Optional.of(customDetectorBeanName)
                        .filter(bf::containsBean)
                        .map(name -> (EncryptablePropertyDetector) bf.getBean(name))
                        .map(tap(bean -> log.info(“Found Custom Detector Bean {} with name: {}”, bean, customDetectorBeanName)))
                        .orElseGet(() -> {
                            if(isCustom) {
                                throw new IllegalStateException(String.format(“Property Detector custom Bean not found with name ‘%s'”, customDetectorBeanName));
                            }
                            log.info(“Property Detector custom Bean not found with name ‘{}’. Initializing Default Property Detector”, customDetectorBeanName);
                            return createDefault(environment);
                        }));
    }

    public DefaultLazyPropertyDetector(ConfigurableEnvironment environment) {
        // 创立一个属性探测器
        singleton = new Singleton<>(() -> createDefault(environment));
    }

    private DefaultPropertyDetector createDefault(ConfigurableEnvironment environment) {
        // 读取所有的属性
        JasyptEncryptorConfigurationProperties props = JasyptEncryptorConfigurationProperties.bindConfigProps(environment);
        // 创立一个默认的属性探测器,读取配置文件中的前缀和后缀
        return new DefaultPropertyDetector(props.getProperty().getPrefix(), props.getProperty().getSuffix());
    }

    /**
      * 是否为解密格局字符串
      */
    @Override
    public boolean isEncrypted(String property) {
        return singleton.get().isEncrypted(property);
    }

    /**
      * 获取真是的加密后的字符串
      */
    @Override
    public String unwrapEncryptedValue(String property) {
        return singleton.get().unwrapEncryptedValue(property);
    }
}
复制代码
在其中是创立了一个 DefaultPropertyDetector 对象
6.1.3 DefaultPropertyDetector
public class DefaultPropertyDetector implements EncryptablePropertyDetector {

    // 默认前缀和后缀
    private String prefix = “ENC(“;
    private String suffix = “)”;

    public DefaultPropertyDetector() {
    }

    public DefaultPropertyDetector(String prefix, String suffix) {
        Assert.notNull(prefix, “Prefix can’t be null”);
        Assert.notNull(suffix, “Suffix can’t be null”);
        this.prefix = prefix;
        this.suffix = suffix;
    }

    @Override
    public boolean isEncrypted(String property) {
        if (property == null) {
            return false;
        }
        final String trimmedValue = property.trim();
        return (trimmedValue.startsWith(prefix) &&
                trimmedValue.endsWith(suffix));
    }

    // 去掉前缀和后缀
    @Override
    public String unwrapEncryptedValue(String property) {
        return property.substring(
                prefix.length(),
                (property.length() – suffix.length()));
    }
}
复制代码
6.2 自定义规定探测器
两种形式自定义

提供一个名为 encryptablePropertyDetector 的 EncryptablePropertyDetector 类型的 Bean 来笼罩默认的实现
如果提供的 bean 名称不为 encryptablePropertyDetector,能够通过批改 yml 中的属性 jasypt.encryptor.property.detector-Bean 为本人的 bean 的名称。

形式

要么自定义类
要么批改 yml 中的前缀和后缀

6.2.1 自定义属性探测器,退出容器
/**
 * 自定义属性探测器
 *  beanName 为 encryptablePropertyDetector
 */
@Bean(name = “encryptablePropertyDetector”)
public EncryptablePropertyDetector encryptablePropertyDetector() {
    return new MyEncryptablePropertyDetector();
}

/**
 * @author HLH
 * @description: 自定义的属性探测器
 * @email 17703595860@163.com
 * @date : Created in 2021/8/19 20:01
 */
public class MyEncryptablePropertyDetector implements EncryptablePropertyDetector {

    /**
     * 是否为能够解密的字符串
     * @param value 全副的字符串
     * @return 是否是解密的字符串,true,是,false,否
     */
    @Override
    public boolean isEncrypted(String value) {
        if (value != null) {
            return value.startsWith(“ENC@”);    // 自定义规定为 ENC@结尾
        }
        return false;
    }

    /**
     * 截取到除了标识之后的值
     * @param value 带前缀
     * @return string 去掉标识符的字符串
     */
    @Override
    public String unwrapEncryptedValue(String value) {
        return value.substring(“ENC@”.length());        // 截取 ENC@之后的字符串
    }
}
复制代码
yml 中的配置
jasypt:
  encryptor:
    # 加密算法
    algorithm: PBEWITHHMACSHA512ANDAES_256
    # 加密应用的盐
    password: jaspyt_password
    property:
       # 批改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用
       # prefix: ENC_(
       # suffix: )
       # 自定义的属性探测器,如果这个是自定义的,那么上述的前缀后缀不失效
       detector-bean: encryptablePropertyDetector
复制代码
6.2.2 批改 yml 中的配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.10.31/mp
    username: root
    # 应用 ENC() 包裹,标识为加密之后的,否则无奈解密,会报错
    # 自定义规定之后,应用 ENC@结尾
    password: ENC@JSrINYe4IBotHndGjX1hnmY3mtPNUJlXjP12cx1+pHqUz2FNXGPu3Frnajh3QCXg
复制代码

  1. 自定义规定的前缀和后缀
    在上述阐明中,在 DefaultLazyPropertyDetector 中是默认是通过配置文件中的规定进行匹配的。默认规定是以 ENC(结尾,以)结尾,能够复写配置来自定义前缀和后缀
    下面第 6 条是自定义了属性探测器,包含了定义规定和过滤字符串
    如果只是想自定义前缀和后缀,那么能够间接批改 yml 中的配置来批改自定义的前缀和后缀
    jasypt:
      encryptor:
        # 加密算法
        algorithm: PBEWITHHMACSHA512ANDAES_256
        # 加密应用的盐
        password: jaspyt_password
        property:
          # 批改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用
          prefix: ENC(
          suffix: )
    复制代码
  2. 间接自定义解密规定
    上述 6 和 7 自定义了解密字符串的规定和解密字符串的过滤,然而真正的解析解决还是 Jasypt 框架来负责的。咱们也能够间接自定义解密的一系列流程。
    8.1 官网解决流程
    8.1.1 官网的注入
    在 EncryptablePropertyResolverConfiguration 类中
    @Bean(
        name = {“lazyEncryptablePropertyResolver”}
    )
    public EncryptablePropertyResolver encryptablePropertyResolver(@Qualifier(“lazyEncryptablePropertyDetector”) EncryptablePropertyDetector propertyDetector, @Qualifier(“lazyJasyptStringEncryptor”) StringEncryptor encryptor, BeanFactory bf, EnvCopy envCopy, ConfigurableEnvironment environment) {
        String customResolverBeanName = envCopy.get().resolveRequiredPlaceholders(RESOLVER_BEAN_PLACEHOLDER);
        boolean isCustom = envCopy.get().containsProperty(“jasypt.encryptor.property.resolver-bean”);
        return new DefaultLazyPropertyResolver(propertyDetector, encryptor, customResolverBeanName, isCustom, bf, environment);
    }
    复制代码
    默认注入的是 DefaultLazyPropertyResolver 然而在其中创立的是 EncryptablePropertyResolver 对象
    8.1.2 EncryptablePropertyResolver

官网默认是通过 EncryptablePropertyResolver 接口来解决解析字符串的

public interface EncryptablePropertyResolver {

    /**
     * 解决所有属性的解密解决
     * 如果为检测到加密规定,那么返回理论为雷同的字符创
     *
     * @param value 属性值
     * @return 如果值未加密,返回原值,如果加密,返回加密之后的值
     */
    String resolvePropertyValue(String value);
}
复制代码

其真实性应用的实现类是 DefaultPropertyResolver 用来真正解决解析。就是通过调用上文中的 StringEncryptor 解决解密,应用 EncryptablePropertyDetector 定义的解密字符串规定定义是否为加密的字符串

public class DefaultPropertyResolver implements EncryptablePropertyResolver {

    private final Environment environment;
    // 默认的或者自定义的 StringEncryptor,用来解密
    private StringEncryptor encryptor;
    // 默认的或者自定义的 EncryptablePropertyDetector,用来定义是否为加密的字符串
    private EncryptablePropertyDetector detector;

    public DefaultPropertyResolver(StringEncryptor encryptor, Environment environment) {
        this(encryptor, new DefaultPropertyDetector(), environment);
    }

    public DefaultPropertyResolver(StringEncryptor encryptor, EncryptablePropertyDetector detector, Environment environment) {
        this.environment = environment;
        Assert.notNull(encryptor, “String encryptor can’t be null”);
        Assert.notNull(detector, “Encryptable Property detector can’t be null”);
        this.encryptor = encryptor;
        this.detector = detector;
    }

    @Override
    public String resolvePropertyValue(String value) {
        return Optional.ofNullable(value)
                .map(environment::resolvePlaceholders)
                .filter(detector::isEncrypted)  // 如果通过属性探测器确认的,才持续
                .map(resolvedValue -> {
                    try {
                        String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 过滤加密规定后的字符串
                        String resolvedProperty = environment.resolvePlaceholders(unwrappedProperty); 
                        return encryptor.decrypt(resolvedProperty); // 解密
                    } catch (EncryptionOperationNotPossibleException e) {
                        throw new DecryptionException(“Unable to decrypt: ” + value + “. Decryption of Properties failed,  make sure encryption/decryption ” +
                                “passwords match”, e);
                    }
                })
                .orElse(value);
    }
}
复制代码
8.2 自定义的解密逻辑
编写本人的解密逻辑类
退出 spring 容器,命名为 encryptablePropertyResolver,或者通过 yml 形式配置自定义 bean 名称
@Bean(“encryptablePropertyResolver”)
public EncryptablePropertyResolver encryptablePropertyResolver(
        StringEncryptor jasyptStringEncryptor, EncryptablePropertyDetector encryptablePropertyDetector) {
    return new MyEncryptablePropertyResolver(jasyptStringEncryptor, encryptablePropertyDetector);
}

/**
 * @author HLH
 * @description: 间接自定义解密规定
 * @email 17703595860@163.com
 * @date : Created in 2021/8/21 21:22
 */
public class MyEncryptablePropertyResolver implements EncryptablePropertyResolver {

    // 解决解密
    private final StringEncryptor encryptor;
    // 属性探测器
    private final EncryptablePropertyDetector detector;

    public MyEncryptablePropertyResolver(StringEncryptor encryptor, EncryptablePropertyDetector detector) {
        this.encryptor = encryptor;
        this.detector = detector;
    }

    /**
     * 解决真正的解密逻辑
     * @param value 原始值
     * @return 如果值未加密,返回原值,如果加密,返回加密之后的值
     */
    @Override
    public String resolvePropertyValue(String value) {
        return Optional.ofNullable(value)
                .filter(detector::isEncrypted)  // 如果通过属性探测器确认的,才持续
                .map(resolvedValue -> {
                    try {
                        String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim()); // 过滤加密规定后的字符串
                        return encryptor.decrypt(unwrappedProperty); // 解密
                    } catch (EncryptionOperationNotPossibleException e) {
                        throw new DecryptionException(“Unable to decrypt: ” + value + “. Decryption of Properties failed,  make sure encryption/decryption ” +
                                “passwords match”, e);
                    }
                })
                .orElse(value);
    }
}
复制代码
yml 配置
jasypt:
  encryptor:
    # 加密算法
    algorithm: PBEWITHHMACSHA512ANDAES_256
    # 加密应用的盐
    password: jaspyt_password
    property:
       # 批改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用
       # prefix: ENC_(
       # suffix: )
       # 自定义的属性探测器,如果这个是自定义的,那么上述的前缀后缀不失效
       detector-bean: encryptablePropertyDetector
       # 自定义解密逻辑类 如果配置了,默认的解析器将不工作
       resolver-bean: encryptablePropertyResolver
复制代码

  1. 自定义过滤器
    在 Jasypt-spring-boot 中,引入了过滤器
    过滤器 filter 容许过滤某些属性,不进行解密。默认状况下,jasypt.encryptor 结尾的所有属性都会将从查看项中排除掉。这是为了配置 Bean,在加载时循环依赖
    9.1 默认解决流程
    9.1.1 官网的注入
    在 EncryptablePropertyResolverConfiguration 类中
    @Bean(
        name = {“lazyEncryptablePropertyFilter”}
    )
    public EncryptablePropertyFilter encryptablePropertyFilter(EnvCopy envCopy, ConfigurableBeanFactory bf) {
        String customFilterBeanName = envCopy.get().resolveRequiredPlaceholders(FILTER_BEAN_PLACEHOLDER);
        boolean isCustom = envCopy.get().containsProperty(“jasypt.encryptor.property.filter-bean”);
        return new DefaultLazyPropertyFilter(envCopy.get(), customFilterBeanName, isCustom, bf);
    }
    复制代码
    于下面的逻辑一样,在 DefaultLazyPropertyFilter 中其实是新建了一个 EncryptablePropertyFilter 对象,默认实现类是 DefaultPropertyFilter
    9.1.2 DefaultPropertyFilter
    public class DefaultPropertyFilter implements EncryptablePropertyFilter {

    // 过滤的和蕴含的,优先读取配置文件的
    private final List<String> includeSourceNames;
    private final List<String> excludeSourceNames;
    private final List<String> includePropertyNames;
    private final List<String> excludePropertyNames;

    public DefaultPropertyFilter() {
        includeSourceNames = null;
        includePropertyNames = null;
        excludeSourceNames = null;
        excludePropertyNames = null;
    }

    public DefaultPropertyFilter(List<String> includeSourceNames, List<String> excludeSourceNames, List<String> includePropertyNames, List<String> excludePropertyNames) {
        this.includeSourceNames = includeSourceNames;
        this.excludeSourceNames = excludeSourceNames;
        this.includePropertyNames = includePropertyNames;
        this.excludePropertyNames = excludePropertyNames;
    }

    // 是否拦挡
    @Override
    public boolean shouldInclude(PropertySource<?> source, String name) {
        // 如果上述四个都没有配置,那么全副放行
        if (isIncludeAll()) {
            return true;
        }

        // 如果是不蕴含的,返回 false,就过滤掉了
        if (isMatch(source.getName(), excludeSourceNames) || isMatch(name, excludePropertyNames)) {
            return false;
        }

        // 如果是蕴含的,就放行
        return isIncludeUnset() || isMatch(source.getName(), includeSourceNames) || isMatch(name, includePropertyNames);

    }

    private boolean isIncludeAll() {
        return isIncludeUnset() && isExcludeUnset();
    }

    private boolean isIncludeUnset() {
        return isEmpty(includeSourceNames) && isEmpty(includePropertyNames);
    }

    private boolean isExcludeUnset() {
        return isEmpty(excludeSourceNames) && isEmpty(excludePropertyNames);
    }

    private boolean isEmpty(List<String> patterns) {
        return patterns == null || patterns.isEmpty();
    }

    // 传递的配置其实是正则,进行正则匹配
    private boolean isMatch(String name, List<String> patterns) {
        return name != null && !isEmpty(patterns) && patterns.stream().anyMatch(name::matches);
    }
}
复制代码
9.2 自定义过滤器
形式

要么自定义过滤器
要么批改 jasypt.encryptor.property.include-names 或者 jasypt.encryptor.property.exclude-names 配置拦挡和放行的资源 key

自定义过滤器类
退出 spring 容器,命名为 encryptablePropertyFilter
/**
 * 自定义的属性拦截器
 * @param configProps Jasypt 官网读取的配置汇合
 * @return 自定义属性拦截器
 */
@Bean(name=”encryptablePropertyFilter”)
public EncryptablePropertyFilter encryptablePropertyFilter(
        Singleton<JasyptEncryptorConfigurationProperties> configProps) {
    return new MyEncryptablePropertyFilter(configProps.get());
}

/**
 * @author HLH
 * @description: 自定义的属性过滤器
 * @email 17703595860@163.com
 * @date : Created in 2021/8/22 13:37
 */
public class MyEncryptablePropertyFilter implements EncryptablePropertyFilter {

    /* jasypt 的所有配置/
    JasyptEncryptorConfigurationProperties jasyptProperties;

    public MyEncryptablePropertyFilter(JasyptEncryptorConfigurationProperties jasyptProperties) {
        this.jasyptProperties = jasyptProperties;
    }

    @Override
    public boolean shouldInclude(PropertySource<?> source, String name) {
        List<String> excludeNames = jasyptProperties.getProperty().getFilter().getExcludeNames();
        List<String> includeNames = jasyptProperties.getProperty().getFilter().getIncludeNames();
        if (CollectionUtils.isEmpty(includeNames) && CollectionUtils.isEmpty(excludeNames)) {
            return true;
        }

        if (isMatch(source.getName(), excludeNames) || isMatch(source.getName(), excludeNames)) {
            return false;
        }

        return CollectionUtils.isEmpty(includeNames) ||
                isMatch(source.getName(), includeNames) ||
                isMatch(name, includeNames);

    }

    /**
     * 正则判断,如果满足,返回 true,如果不满足,返回 false
     * @param name 配置的 key
     * @param patterns 正则列表
     * @return 如果满足,返回 true,如果不满足,返回 false
     */
    private boolean isMatch(String name, List<String> patterns) {
        return name != null && !CollectionUtils.isEmpty(patterns) && patterns.stream().anyMatch(name::matches);
    }

}
复制代码
yml 配置
jasypt:
  encryptor:
    # 加密算法
    algorithm: PBEWITHHMACSHA512ANDAES_256
    # 加密应用的盐
    password: jaspyt_password
    property:
      # 批改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用
      # prefix: ENC_(
      # suffix: )
      # 自定义的属性探测器,如果这个是自定义的,那么上述的前缀后缀不失效
      detector-bean: encryptablePropertyDetector
      # 自定义解密逻辑类 如果配置了,默认的解析器将不工作
      resolver-bean: encryptablePropertyResolver
      # 过滤器的 bean
      filter-bean: encryptablePropertyFilter
      # 过滤器配置,正则
      filter:
        # 默认蕴含的
        include-names:
        # 默认拦挡的,默认拦挡 jasypt.encryptor 的配置
        exclude-names:
          – ^jasypt.encryptor.*
复制代码

  1. 应用 mvn 插件加密解密
    应用代码的形式比拟不不便,还须要编码实现,如果不想编码,简略的进行加密解密,就能够应用 maven 的插件,应用 mvn 命令进行加密解密
    10.1 引入 Jasypt 的 maven 插件
    <build>
        <plugins>
            <!– Jasypt 的 maven 插件 –>
            <plugin>
                <groupId>com.github.ulisesbocchio</groupId>
                <artifactId>jasypt-maven-plugin</artifactId>
                <version>3.0.2</version>
            </plugin>
        </plugins>
    </build>
    复制代码
    10.2 加密
    应用 jasypt-maven-plugin 插件加密明文明码:(如果配置项是默认值,能够不指定)
    mvn jasypt:encrypt-value -Djasypt.encryptor.password=”jaspyt_password” -Djasypt.plugin.value=”root” -Djasypt.encryptor.algorithm=”PBEWITHHMACSHA512ANDAES_256″
    复制代码

jasypt.encryptor.password 是秘钥,尽量简单!不能放在代码和配置文件外面!不能透露
jasypt.plugin.value 是要加密的明文明码
jasypt.encryptor.algorithm 默认加密算法是 PBEWITHHMACSHA512ANDAES_256,须要有 JCE(Java Cryptography Extension)反对,如果不想装置 JCE,能够应用 PBEWithMD5AndDES 算法。windows 下的 jdk 自带

进入我的项目所在的目录,输出命令,胜利加密
10.3 解密
应用 jasypt-maven-plugin 插件解密密文明码:(如果配置项是默认值,能够不指定)
mvn jasypt:decrypt-value -Djasypt.encryptor.password=”jaspyt_password” -Djasypt.plugin.value=”pqsp6kvVfBcKoEltxP9MilGGRo8EE506mDWAuTFIKePDXMeArta13bT6Hl8QqVlC” -Djasypt.encryptor.algorithm=”PBEWITHHMACSHA512ANDAES_256″
复制代码

jasypt.encryptor.password 是秘钥,尽量简单!不能放在代码和配置文件外面!不能透露
jasypt.plugin.value 是要加密的明文明码,有 ENC() 包裹或者不包裹都能够
jasypt.encryptor.algorithm 默认加密算法是 PBEWITHHMACSHA512ANDAES_256,须要有 JCE(Java Cryptography Extension)反对,如果不想装置 JCE,能够应用 PBEWithMD5AndDES 算法。windows 下的 jdk 自带

进入我的项目所在的目录,输出命令,胜利加密

  1. 思维导图
    最初再来一张思维导图
退出移动版