package com.jadyer.seed.boot; import com.jadyer.seed.comm.util.LogUtil; import org.jasypt.encryption.StringEncryptor; import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; import org.jasypt.properties.PropertyValueEncryptionUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.io.support.ResourcePropertySource; /** * 這裡參考了https://github.com/ulisesbocchio/jasypt-spring-boot * ---------------------------------------------------------------------------------------------- * 下面演示一下Windows中的加解密 * 根據http://www.jasypt.org/cli.html提示到http://www.jasypt.org/download.html下載到jasypt-1.9.2-dist.zip * 解壓jasypt-1.9.2-dist.zip得到文件夾,并進入目錄為C:\Users\Jadyer\Desktop\jasypt-1.9.2\bin的命令行窗口 * encrypt.bat input=xuanyu password=https://jadyer.cn/ stringOutputType=hexadecimal * decrypt.bat input=B9063BE29557963568F929EBBD682B5C password=https://jadyer.cn/ stringOutputType=hexadecimal * 注意:每一次生成的密文都是不同的,但都可以解密成xuanyu * ---------------------------------------------------------------------------------------------- * 关于实现EnvironmentAware.java接口 * setEnvironment()会在系统启动时被执行,可以通过它获取到系统环境变量和application配置文件中的变量 * 然后就可以通过environment.getProperty()等方法获取系统环境变量或application配置文件中的变量 * ---------------------------------------------------------------------------------------------- * 关于@PropertySource注解 * 它可以从配置文件中,读取对应的key-value,然后会放到Environment * 它可以读取'键值对'的配置文件,且支持读取多个配置文件中的属性值,读取后会放到Environment中 * ---------------------------------------------------------------------------------------------- * Created by 玄玉<https://jadyer.cn/> on 2016/5/14 13:22. */ @Configuration @ConditionalOnClass(StringEncryptor.class) @PropertySource(value={"${jasypt.file:classpath:config/encrypted.properties}"}) public class JasyptConfiguration implements EnvironmentAware { private Environment environment; @Override public void setEnvironment(Environment environment) { this.environment = environment; } private String getProperty(Environment environment, String key, String defaultValue){ if(null == environment.getProperty(key)){ LogUtil.getLogger().info("未找到加密配置:{},系统自动取默认值:{}", key, defaultValue); } return environment.getProperty(key, defaultValue); } /** * <p> * BeanPostProcessorBeanFactoryPostProcessor區別可參考http://www.shouce.ren/api/spring2.5/ch03s07.html<br/> * 大致就是BeanFactoryPostProcessor用於Spring註冊BeanDefinition之後,實例化BeanDefinition之前,可修改Bean配置<br/> * 比如常見的配置數據庫連接池dataSource,用戶名和密碼放在獨立的一個配置文件中,然後用${jdbc.name}引用裏面的配置 * </p> */ @Bean public BeanFactoryPostProcessor propertySourcesPostProcessor(){ PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor(); SimpleStringPBEConfig config = new SimpleStringPBEConfig(); //Master Password used for Encryption/Decryption of properties. config.setPassword(this.getProperty(this.environment, "jasypt.encryptor.password", "https://jadyer.cn/")); //Encryption/Decryption Algorithm to be used by Jasypt. //For more info on how to get available algorithms visit: <a href="http://www.jasypt.org/cli.html"/>Jasypt CLI Tools Page</a>. config.setAlgorithm(this.getProperty(this.environment, "jasypt.encryptor.algorithm", "PBEWithMD5AndDES")); //Number of hashing iterations to obtain the signing key. config.setKeyObtentionIterations(this.getProperty(this.environment, "jasypt.encryptor.keyObtentionIterations", "1000")); //The size of the pool of encryptors to be created. config.setPoolSize(this.getProperty(this.environment, "jasypt.encryptor.poolSize", "1")); //The name of the {@link java.security.Provider} implementation to be used by the encryptor for obtaining the encryption algorithm. config.setProviderName(this.getProperty(this.environment, "jasypt.encryptor.providerName", "SunJCE")); //A {@link org.jasypt.salt.SaltGenerator} implementation to be used by the encryptor. config.setSaltGeneratorClassName(this.getProperty(this.environment, "jasypt.encryptor.saltGeneratorClassname", "org.jasypt.salt.RandomSaltGenerator")); //Specify the form in which String output will be encoded. {@code "base64"} or {@code "hexadecimal"}. config.setStringOutputType(this.getProperty(this.environment, "jasypt.encryptor.stringOutputType", "hexadecimal")); encryptor.setConfig(config); return new EnableEncryptablePropertySourcesPostProcessor(encryptor); } private class EnableEncryptablePropertySourcesPostProcessor implements BeanFactoryPostProcessor { private StringEncryptor encryptor; EnableEncryptablePropertySourcesPostProcessor(StringEncryptor encryptor){ this.encryptor = encryptor; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { MutablePropertySources propertySources = ((ConfigurableEnvironment)environment).getPropertySources(); for(org.springframework.core.env.PropertySource<?> obj : propertySources){ if(obj instanceof ResourcePropertySource){ propertySources.replace(obj.getName(), new PropertySourceWrapper((ResourcePropertySource)obj)); } } } private class PropertySourceWrapper extends MapPropertySource { PropertySourceWrapper(ResourcePropertySource propertySource) { super(propertySource.getName(), propertySource.getSource()); } @Override public Object getProperty(String name) { Object value = super.getProperty(name); if(value instanceof String){ String stringValue = String.valueOf(value); //查看isEncryptedValue()源碼可看到它是根據ENC()判斷是否需要解密的 if(PropertyValueEncryptionUtils.isEncryptedValue(stringValue)){ value = PropertyValueEncryptionUtils.decrypt(stringValue, encryptor); } } //return super.getProperty(name); return value; } } } }