这样加密SpringBoot 配置文件,更加安全!

springboot集成jasypt 遇到 String Encryptor custom Bean not found with name ‘xxxEncryptor‘ 阅读详情

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 } } 复制代码

3. 使用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(); } 复制代码

4. Jasypt配置详解

所有配置都在JasyptEncryptorConfigurationProperties类中定义,我们只需要在yml中配置属性,即可达到重写的目的

Jasypt使用StringEncryptor来解密属性。如果Spring上下文中找不到自定义的StringEncryptor,就会自动创建一个,可以通过以下属性进行配置

唯一需要的属性是加密的盐,其余的可以使用默认值。虽然所有这些属性都可以在属性文件中生命,但加密所使用的盐不应该存储在属性文件中,而是应该通过系统属性、命令行参数或者环境变量传递,只要他的名称是jasypt.encryptor.password,它就可以工作。

倒数第二个属性jasypt.encryptor.proxyPropertySources用于只是jasypt spring boot如何拦截属性值进行解密。默认值false使用PropertySource、EnumerablePropertySource和MapPropertySource的自定义包装器实现。当为true时,拦截机制将在每个特定的PropertySource实现上使用CGLib代理。在某些必须保留原始PropertySource类型的场景中,这可能很有用。

5. 自定义加密

默认情况下,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; } 复制代码

6. 自定义属性探测器

属性探测器为判断一个属性值是否为加密后的字符串,并且截取真实字符串

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 p
ublic 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 复制代码

7. 自定义规则的前缀和后缀

在上述说明中,在DefaultLazyPropertyDetector中是默认是通过配置文件中的规则进行匹配的。默认规则是以ENC(开头,以)结尾,可以复写配置来自定义前缀和后缀

上面第6条是自定义了属性探测器,包括了定义规则和过滤字符串

如果只是想自定义前缀和后缀,那么可以直接修改yml中的配置来修改自定义的前缀和后缀

jasypt: encryptor: 
# 加密算法 algorithm: PBEWITHHMACSHA512ANDAES_256 # 加密使用的盐 password: jaspyt_password property: 
# 修改默认的前缀和后缀,如果自定义属性探测器,那么此项配置不起作用 prefix: ENC( suffix: ) 复制代码

8. 直接自定义解密规则

上述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

  1. 官方默认是通过EncryptablePropertyResolver接口来处理解析字符串的

public interface EncryptablePropertyResolver { 
/** * 处理所有属性的解密处理 * 如果为检测到加密规则,那么返回实际为相同的字符创 * * @param value 属性值 * @return 如果值未加密,返回原值,如果加密,返回加密之后的值 */ 
String resolvePropertyValue(String value); } 复制代码
  1. 其真实性使用的实现类是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 复制代码

9. 自定义过滤器

在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.* 复制代码

10. 使用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自带

进入项目所在的目录,输入命令,成功加密

11. 思维导图

最后再来一张思维导图

​

Springboot之Jasypt配置文件加密/解密 前言在大多数项目中,配置文件中的 mysql 数据库密码、redis 密码等其他敏感性密码都是以明文形式存在,这种配置本身没有任何问题,但是,在某些情况下,可能会对公司造成不可挽救的损失,比如:某一天,小明因为加班过度,头脑发昏,不小心把公司项目上传到自己的 GitHub 仓库里面了,导致的后果就是,公司数据库用户名密码泄露,被某些大佬加以利用…所以,基于上面这种情况,加入配置文件中数据库用户密码等其他敏感信息都是经过加密处理过的呢???是不是可以大概率避免这种情况。Jasypt 因此应运而生。什么是Jas 阅读详情

相关推荐

SpringBoot配置文件明文加密

在日常开发中,项目中会有很多配置文件。比如SpringBoot项目核心的数据库配置、Redis账号密码配置都在propertiesyml配置文件中。如果这些信息以明文的方式存储,你的电脑被拿去修理,就会容易泄露,一旦被其他人获取到……你懂得…… 那么如何将配置文件中的明文信息加密存储就变得至关重要,让我们一起来看下吧。你想给你的兄弟分享你的考验资料,为了保证安全性,你选择使用加密。为了保证安全性不能让人随便看到,是首先使用对称加密。你给它设置一个了密码。但是你在发送过程中内容被隔壁张三截获,在你告知。

2401_88858891的博客 1419

springboot jasypt2.x与jasypt3.x的使用

springboot jasypt2.x与jasypt3.x的使用 如果我们把大量的配置信息都放在配置文件中是会有安全隐患的,那么如何消除这个隐患呢?最直接的方式就是把配置信息中的一些敏感信息(比如数据库密码、中间件密码)加密,然后程序在获取这些配置的时候解密,就可以达到目的。这个时候,jasypt框架就派上用场了。

秃头的博客 5126

Springboot AOP实现指定敏感字段数据加密 (数据加密篇 二)

前言 最近项目组开始关注一些敏感数据的明文相关的事宜 , 其实这些东西也是都有非常成熟的解决方案。 既然最近着手去解决这些事情,那么也顺便给还未了解的大伙普及一下。 这个系列就暂短的分成两篇 : 第一篇 yml配置文件里敏感数据的加密 第二篇 传入数据敏感数据的加密存储 本篇是第二篇 正文 先看看效果 : 数据存入数据库表内, 手机号phone和邮箱email 属于敏感数据,我们需要密文存储 : 但是我们想动态一点, 那些插入接口 需...

默默不代表沉默 1万+

String Encryptor custom Bean not found with name ‘jasyptStringEncryptor‘...

apollo和jasypt冲突

遨游大海 2348

Springboot yml配置参数加密 ,jasypt自定义解密器(拓展篇)

前言 最近项目组开始关注一些敏感数据的明文相关的事宜 , 其实这些东西也是都有非常成熟的解决方案。 既然最近着手去解决这些事情,那么也顺便给还未了解的大伙普及一下。Springboot yml配置参数数据加密 (数据加密篇 一)_默默不代表沉默-优快云博客_springboot接口加密 Springboot AOP实现指定敏感字段数据加密 (数据加密篇 二)_默默不代表沉默-优快云博客 Springboot 使用mysql加密解密函数 (数据加密篇 三)_默默不代表沉默-优快云博客 ..

默默不代表沉默 4881

StringEncryptor:加密的小工具-使用GUI解密字符串

StringEncryptor:加密的小工具-使用GUI解密字符串

Spring Boot 配置文件这样加密,才足够安全!

在使用Springboot时,通常很多信息都是在application.yml中直接明文配置的,比如数据库链接信息,redis链接信息等等。但是这样是不安全的。所以需要对敏感数据进行加密,这样防止密码泄露Jasypt这个库为我们解决了这个问题,实现了springboot配置的自定加密加密源码对应地址:2.1 引入依赖 2.2 配置application信息jasypt配置 2.3 加密解密测试 3. 使用Jasypt加密后的字符串代替数据库密码 3.1 使用加密类进行加密密码 root 加密之

m0_71777195的博客 4873

基于Hadoop的NBA篮球球员大数据分析与可视化系统大数据分析系统python的项目(源码+lw+部署文档+讲解等)

本系统以 Hadoop 为基础,致力于对 NBA 篮球球员的海量数据进行深入分析与可视化呈现。它能够收集来自多个数据源的丰富数据,包括球员比赛统计数据、身体素质数据、技术特点数据等。利用 Hadoop 的分布式存储和计算能力,对这些大规模数据进行高效处理。通过数据分析算法,挖掘球员的潜在价值和特点,如球员的得分能力趋势、篮板球效率变化、不同位置球员的技术差异等。同时,借助先进的可视化技术,将分析结果以直观的图表、图形等形式展示出来。教练和球队管理层可以通过可视化界面清晰地了解球员的综合表现和发展态势,从而制

QQ3359892174的博客 1314

SpringBoot 配置文件这样加密,才足够安全!

唯一需要的属性是加密的盐,其余的可以使用默认值。虽然所有这些属性都可以在属性文件中生命,但加密所使用的盐不应该存储在属性文件中,而是应该通过系统属性、命令行参数或者环境变量传递,只要他的名称是。但是这样是不安全的。上述6和7自定义了解密字符串的规则和解密字符串的过滤,但是真正的解析处理还是Jasypt框架来负责的。使用代码的方式比较不方便,还需要编码实现,如果不想编码,简单的进行加密解密,就可以使用maven的插件,使用mvn命令进行加密解密。类中定义,我们只需要在yml中配置属性,即可达到重写的目的。

m0_74931226的博客 3451

告别夜间噪点!用瑞芯微RV1126B的AI-ISP,手把手教你打造0.01Lux超低光摄像头

本文详细介绍了如何利用瑞芯微RV1126B芯片的AI-ISP技术,打造0.01Lux超低光摄像头,解决夜间噪点问题。通过AI算法与图像信号处理的深度融合,RV1126B的3TOPS边缘算力实现了像素级AI降噪和语义感知增强,显著提升低光环境下的图像质量。文章包含硬件选型、软件配置和实战调优指南,助力开发者在AIoT领域实现高性能视觉应用。

weixin_33725722的博客 565

手把手教你用Microsoft AEC Challenge数据集训练自己的回声消除模型(附完整代码)

本文详细介绍了如何使用Microsoft AEC Challenge数据集训练专业的回声消除模型,包括环境准备、数据清洗、模型架构设计、训练流程和实际部署注意事项。通过完整的代码示例和实战指南,帮助开发者快速掌握AEC技术,提升语音通信系统的回声消除效果。

weixin_27697385的博客 458

网络安全——SpringBoot配置文件明文加密

在日常开发中,项目中会有很多配置文件。比如SpringBoot项目核心的数据库配置、Redis账号密码配置都在propertiesyml配置文件中。如果这些信息以明文的方式存储,你的电脑被拿去修理,就会容易泄露,一旦被其他人获取到……你懂得…… 那么如何将配置文件中的明文信息加密存储就变得至关重要,让我们一起来看下吧。你想给你的兄弟分享你的考验资料,为了保证安全性,你选择使用加密。为了保证安全性不能让人随便看到,是首先使用对称加密。你给它设置一个了密码。但是你在发送过程中内容被隔壁张三截获,在你告知。

2401_88326365的博客 1975

乐鑫ESP32-C6产测全流程:RAM固件测试与阈值校准实战指南

Wi-Fi模组量产测试是保障IoT设备射频性能与硬件可靠性的关键环节,其核心在于基于RAM的无损固件加载、可配置的阈值判定机制及多工位协同控制。该流程依托串口协议与结构化配置(如JSON阈值文件、.bin测试固件),实现RF性能(fb_rssi、tx_power)、GPIO导通性、Flash ID识别与固件版本校验等原子化测试项的自动化执行。技术价值体现在避免Flash擦写风险、支持动态温补与在线学习校准,并无缝对接MES系统实现质量数据闭环。典型应用场景包括ESP32-C6/C3/S2等乐鑫全系Wi-Fi

weixin_35756690的博客 311

SpringBoot配置文件中密码属性加密

SpringBoot配置文件中密码属性加密 本文主要介绍了SpringBoot配置文件中的明文密码如何加密保存,读取以及对于自定义的加密算法加密的参数如何保存和读取。 背景 为了安全的需要,一些重要的信息比如数据库密码不能明文保存在配置文件中,需要进行加密之后再保存。SpringBoot可以使用jasypt-spring-boot这个组件来为配置属性提供加密的支持。 集成jasypt-spring-boot到项目中 根据官方README文档,可以有三种方式集成jasypt-spring-boot到项目中。

qq_32238611的博客 1万+

C#读取CAD文件(dwg/dxf)并处理

项目要求识别CAD图纸(图纸内容与现实事物比例是1:1)中的内容,并提取出一些关键信息。这里的CAD图纸是指CAD文件,包含多种格式,dwg/dxf/dwf/stl/pdf等等。识别其中内容,主要指文件中的图元信息(也叫实体Entity),指线段、圆弧、矩形等图形元素。得到图元基础信息(比如长度、坐标、粗细)后,进一步做处理(如得到交点、得到线段间间隔、圆弧与线段切点等)。听起来有点难,因为作为软件工程师,对CAD相关事物并不了解,它是未知的;

三千幻想乡 1万+

【架构师面试-缓存与搜索-1】-缓存与缓存置换策略源码实现

1:什么是缓存 缓存:加速数据访问的存储,降低延迟(latency),提升吞吐量(Throughput)的利器。 1:缓存演进历史 1. 查库 2. ConcurrentHashMap 3. LRU 4. Guava Cache 5. 分布式缓存(redis,MemCache) 6. 多级缓存 2:在什么地方加缓存 缓存对于每个开发者来说是相当熟悉了,为了提高程序的性能我们会去加缓存,但是在什么地方加缓存,如何加缓存呢? 举个栗子:假设一个网站,需要提高性能,缓存可以放在浏览器,可以放

chongfa2008的博客 6440
上一篇: 当你碰到了MySQL中的死锁,你了解这些机制吗?
下一篇: 2022最新JUC+多线程面试题
Java_LingFeng
博客等级 码龄4年 505粉丝 259原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值