【问题标题】:Creating a custom Jasypt PropertySource in Springboot在 Springboot 中创建自定义 Jasypt PropertySource
【发布时间】:2014-06-27 11:49:52
【问题描述】:

我正在使用 Spring Boot 创建一个访问数据库的简单 Web 应用程序。我通过在application.properties 中设置spring.datasource.* 属性来利用数据源的自动配置功能。这一切都非常出色,而且速度非常快 - @Spring 的工作人员很棒!

我公司的政策是不应该有明文密码。因此我需要对sping.datasource.password 进行加密。经过一番挖掘,我决定创建一个 org.springframework.boot.env.PropertySourceLoader 实现,它创建一个 jasypt org.jasypt.spring31.properties.EncryptablePropertiesPropertySource,如下所示:

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;
    }
}

然后我用META-INF/spring.factories 文件将它打包到它自己的jar 中,如下所示:

org.springframework.boot.env.PropertySourceLoader=com.mycompany.spring.boot.env.EncryptedPropertySourceLoader

当使用 mvn spring-boot:run 从 maven 运行时,这非常有效。当我使用java -jar my-app.war 将其作为独立战争运行时,就会出现问题。当我尝试连接到数据库时,应用程序仍然加载但失败,因为密码值仍然是加密的。添加日志记录显示EncryptedPropertySourceLoader 从未加载。

对我来说,这听起来像是一个类路径问题。在 maven 下运行时,jar 加载顺序是严格的,但是一旦在嵌入 tomcat 下,就没有什么可以说我的自定义 jar 应该在 Spring Boot 之前加载。

我尝试将以下内容添加到我的 pom.xml 以确保保留 classpth,但它似乎没有任何效果。

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

有人有什么想法吗?提前致谢。

更新:

向前迈出一步:我已经设法通过让EncryptedPropertySourceLoader 类实现org.springframework.core.PriorityOrdered 接口并从getOrder() 返回HIGHEST_PRECEDENCE 来解决这个问题。这现已解决了 PropertySourceLoader 未被使用的问题。但是,它现在在尝试解密属性时抛出以下错误:

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 运行时它确实有效,我想我可以打折扣。可能是包装问题...

【问题讨论】:

  • spring.factoriesWEB-INF/lib 的罐子里?
  • 是的。打开从 maven 生成的 WAR 会得到my-app.war!WEB-INF/lib/utility.jar!META-INF/spring.factories
  • 我想这是一个类加载器问题。它可以在 JAR(而不是 WAR)中工作吗?
  • 查看更新:它现在使用自定义 PropertySourceLoader(因为它现在实现了 PriorityOrdered),但仍然面临一些我怀疑与 maven 与可执行 jar 的差异有关的问题。
  • 它可以在 JAR 中工作吗?

标签: spring-boot jasypt


【解决方案1】:

这里有两个问题。

1) EncryptedPropertySourceLoader 需要加载高于标准 PropertiesPropertySourceLoader。这可以通过如下实现 PriorityOrder 接口来实现:

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.PropertySourceLoaderorg.springframework.core.io.support.SpringFactoriesLoader 类使用org.springframework.core.OrderComparator 对结果进行排序。这意味着应首先返回此类,并将负责为 *.proerpties 文件提供 PropertySourceLoader 实现。

2) 第二个是可执行 JAR/WAR 的类加载问题,这似乎是由 Windows 上 Spring Boot 的 1.1.2.RELEASE 版本中的错误引起的。降到版本 1.1.1.RELEASE 或版本 1.1.3.RELEASE 解决了在 maven 之外运行时未加载类和属性文件的各种问题。

【讨论】:

  • 我使用完全相同的代码和 spring.factoryies 文件,版本为 1.2.3.RELEASE,但它没有加载我的 EncryptedPropertySourceLoader。为了指示负载,我从 load 方法中抛出了 RuntimeException,但似乎没有调用此方法。我错过了什么吗?
  • 这里是完成问题的链接stackoverflow.com/questions/31824601/…
【解决方案2】:

你可以试试这个:jasypt-spring-boot 它基本上用可加密版本包装了 Environment 中存在的所有 PropertySource。导入库后必须做的两件事(如果使用 maven,则添加依赖项)是使用 @EnableEncryptableProperties 注释 @Configuration 类,并通过属性配置加密算法和密码。

【讨论】:

  • 嗨 Ulises,这个库 jasypt 过时了吗?它自 2014 年 3 月以来没有更新。在项目中使用它安全吗?
  • 我已经使用它几年来加密敏感属性。该库只是 JDK 提供的算法的包装器。它只是让它们更易于使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-16
  • 2021-06-16
  • 2019-09-03
  • 1970-01-01
  • 1970-01-01
  • 2016-06-13
  • 2011-12-13
相关资源
最近更新 更多