在Springboot中创建自定义Jasypt PropertySource [英] Creating a custom Jasypt PropertySource in Springboot
问题描述
我正在使用Spring Boot创建一个访问数据库的简单Web应用程序.我通过在application.properties
中设置spring.datasource.*
属性来利用DataSource的自动配置功能.一切都很棒,而且非常快-伟大的工作人员@ Spring!
I'm using Spring Boot to create a simple web application which accesses a database. I'm taking advantage of the autoconfiguration functionality for the DataSource by setting up spring.datasource.*
properties in application.properties
. That all works brilliantly and was very quick - great work guys @ Spring!
我公司的政策是不应使用明文密码.因此,我需要对sping.datasource.password
进行加密.经过一番挖掘后,我决定创建一个org.springframework.boot.env.PropertySourceLoader
实现,该实现将创建一个jasypt org.jasypt.spring31.properties.EncryptablePropertiesPropertySource
,如下所示:
My companys policy is that there should be no clear text passwords. Therefore I need to have the sping.datasource.password
encrypted. After a bit of digging around I decided to create a org.springframework.boot.env.PropertySourceLoader
implementation which creates a jasypt org.jasypt.spring31.properties.EncryptablePropertiesPropertySource
as follows:
public class EncryptedPropertySourceLoader implements PropertySourceLoader
{
private final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
public EncryptedPropertySourceLoader()
{
//TODO: this could be taken from an environment variable
this.encryptor.setPassword("password");
}
@Override
public String[] getFileExtensions()
{
return new String[]{"properties"};
}
@Override
public PropertySource<?> load(final String name, final Resource resource, final String profile) throws IOException
{
if (profile == null)
{
final Properties props = PropertiesLoaderUtils.loadProperties(resource);
if (!props.isEmpty())
{
return new EncryptablePropertiesPropertySource(name, props, this.encryptor);
}
}
return null;
}
}
然后我将其包装在它自己的jar中,并带有一个META-INF/spring.factories
文件,如下所示:
I then packaged this in it's own jar with a META-INF/spring.factories
file as follows:
org.springframework.boot.env.PropertySourceLoader=com.mycompany.spring.boot.env.EncryptedPropertySourceLoader
当使用mvn spring-boot:run
从maven运行时,这非常理想.当我使用java -jar my-app.war
作为独立战争运行它时,会发生问题.该应用程序仍然加载,但是当我尝试连接到数据库时由于密码值仍然被加密而失败.添加日志记录显示EncryptedPropertySourceLoader
从未加载.
This works perfectly when run from maven using mvn spring-boot:run
. The problem occurs when I run it as a standalone war using java -jar my-app.war
. The application still loads but fails when I try to connect to the database as the password value is still encrypted. Adding logging reveals that the EncryptedPropertySourceLoader
is never loaded.
对我来说,这听起来像是类路径问题.在maven下运行时,jar的加载顺序很严格,但是一旦进入了tomcat的tomcat,就无话可说,我的自定义jar应该在Spring Boot之前加载.
To me this sounds like a classpath issue. When run under maven the jar loading order is strict but once under the embebed tomcat there is nothing to say that my custom jar should be loaded before Spring Boot.
我尝试将以下内容添加到pom.xml中,以确保保留了classpth,但它似乎没有任何作用.
I've tried adding the following to my pom.xml to ensure the classpth is preserved but it doesn't seem to have had any effect.
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<mainClass>${start-class}</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
有人有什么想法吗?预先感谢.
Does anyone have any ideas? Thanks in advance.
更新:
向前迈进:我已经设法通过使EncryptedPropertySourceLoader
类实现org.springframework.core.PriorityOrdered
接口并从getOrder()
返回HIGHEST_PRECEDENCE
来解决此问题.现在,这已解决了不使用PropertySourceLoader的问题.但是,现在尝试解密属性时会引发以下错误:
A step forward: I've managed to fix this by having the EncryptedPropertySourceLoader
class implement org.springframework.core.PriorityOrdered
interface and returning HIGHEST_PRECEDENCE
from getOrder()
. This has now fixed the issue of the PropertySourceLoader not being used. However it's now throwing the following error when it tries to decrypt the properties:
org.jasypt.exceptions.EncryptionInitializationException: java.security.NoSuchAlgorithmException: PBEWithMD5AndDES SecretKeyFactory not available
at org.jasypt.encryption.pbe.StandardPBEByteEncryptor.initialize(StandardPBEByteEncryptor.java:716)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.initialize(StandardPBEStringEncryptor.java:553)
at org.jasypt.encryption.pbe.StandardPBEStringEncryptor.decrypt(StandardPBEStringEncryptor.java:705)
at org.jasypt.properties.PropertyValueEncryptionUtils.decrypt(PropertyValueEncryptionUtils.java:72)
at org.jasypt.properties.EncryptableProperties.decode(EncryptableProperties.java:230)
at org.jasypt.properties.EncryptableProperties.get(EncryptableProperties.java:209)
at org.springframework.core.env.MapPropertySource.getProperty(MapPropertySource.java:36)
at org.springframework.boot.env.EnumerableCompositePropertySource.getProperty(EnumerableCompositePropertySource.java:49)
at org.springframework.boot.context.config.ConfigFileApplicationListener$ConfigurationPropertySources.getProperty(ConfigFileApplicationListener.java:490)
同样,从mvn spring-boot:run
运行时不会发生,但从可执行war文件运行时会发生.两种方案都使用相同的JVM(jdk1.6.0_35). Google/Stackoverflow上的结果表明这是Java安全策略的一个问题,但是由于它在从Maven运行时确实有效,我认为我可以对此予以保留.可能是包装问题...
Again this doesn't happen when running from mvn spring-boot:run
but does happen when running from the executable war file. Both scenarios use the same JVM (jdk1.6.0_35). Results on Google/Stackoverflow suggest this is an issue with the java security policy but as it does work when run from maven I think I can discount that. Possibly a packaging issue...
推荐答案
这里有两个问题.
1)EncryptedPropertySourceLoader的加载需要比标准PropertiesPropertySourceLoader的加载高.这可以通过实现如下的PriorityOrder接口来实现:
1) The EncryptedPropertySourceLoader needs to be loaded higher than then standard PropertiesPropertySourceLoader. This can be achieved by implementing the PriorityOrder interface as follows:
public class EncryptedPropertySourceLoader implements PropertySourceLoader, PriorityOrdered
{
private final StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
public EncryptedPropertySourceLoader()
{
this.encryptor.setPassword("password"); //TODO: this could be taken from an environment variable
}
@Override
public String[] getFileExtensions()
{
return new String[]{"properties"};
}
@Override
public PropertySource<?> load(final String name, final Resource resource, final String profile) throws IOException
{
if (profile == null)
{
//load the properties
final Properties props = PropertiesLoaderUtils.loadProperties(resource);
if (!props.isEmpty())
{
//create the encryptable properties property source
return new EncryptablePropertiesPropertySource(name, props, this.encryptor);
}
}
return null;
}
@Override
public int getOrder()
{
return HIGHEST_PRECEDENCE;
}
}
从META-INF/spring.factories
加载org.springframework.boot.env.PropertySourceLoader
的org.springframework.core.io.support.SpringFactoriesLoader
类使用org.springframework.core.OrderComparator
对结果进行排序.意味着该类应首先返回,并将负责为* .proerpties文件提供PropertySourceLoader实现.
The org.springframework.core.io.support.SpringFactoriesLoader
class which loads the org.springframework.boot.env.PropertySourceLoader
from the META-INF/spring.factories
orders the results using org.springframework.core.OrderComparator
. Meaning that this class should be returned first and will be given the responsibility of providinging the PropertySourceLoader implementation for *.proerpties files.
2)第二个问题是可执行JAR/WAR的类加载问题,这似乎是由Windows上的Spring Boot版本1.1.2.RELEASE中的错误引起的.降级到1.1.1.RELEASE版本或1.1.3.RELEASE版本解决了在maven之外运行时类和属性文件未加载的各种问题.
2) The second is a class loading issue with the executable JAR/WAR which seems to be caused by a bug in version 1.1.2.RELEASE of Spring Boot on Windows. Dropping to version 1.1.1.RELEASE or to version 1.1.3.RELEASE solves the various issues with classes and proerpties file not being loaded when run outside of maven.
这篇关于在Springboot中创建自定义Jasypt PropertySource的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!