静态加密方法:如何使用Spring配置文件从属性获取密码

时间:2013-11-12 23:59:46

标签: spring security spring-security morphia

我们正在使用prePersist()(使用Morphia)和实体的getter透明地加密/解密我们的一些数据库属性。为了保持实体的美观和干净,我们使用的是静态方法。它看起来像这样:

@Override
@PrePersist
public void prePersist() {
    super.prePersist();
    if(password != null){
        if(passwordEncrypted == null){
            passwordEncrypted = new EncryptedString();
        }
        passwordEncrypted.setEncryptedAttribute(AESEncryptor.encrypt(password, passwordEncrypted.getSalt()));
    }
}

请注意,我们没有在postLoad()方法中进行解密,因为并不总是需要加密属性,我们希望避免性能开销。不幸的是,这会排除@EntityListener,如http://invariantproperties.com/2012/11/25/database-encryption-using-jpa-listeners/中所述。

public String getPassword() {
    if((password == null) && (passwordEncrypted != null)){
        password = AESEncryptor.decrypt(passwordEncrypted.getEncryptedAttribute(), passwordEncrypted.getSalt());
    }
    return password;
}

现在我们要将加密密码保存在我们的属性文件中,并且应该加载来自正确配置文件(prod,stage,dev)的密码。

加密代码看起来像这样 - getPassword应该通过Spring加载:

public static String encrypt(String input, String salt) {
    TextEncryptor encryptor = Encryptors.text(getPassword(), salt);
    String cipher = null;
    try {
        cipher = encryptor.encrypt(input);
    } catch(Exception e){
        LOG.error("Could not encrypt the input '{}', be sure to check the password for illegal characters", input);
    }
    return cipher;
}

虽然可以使用Spring加载静态变量(例如http://www.connorgarvey.com/blog/?p=105),但这非常hackish并且几乎总是不鼓励。此外,我们不确定这是否可能无法解决垃圾收集问题。

怎么可能/应该这样做?

1 个答案:

答案 0 :(得分:1)

如果使用XML进行配置,则可以使用org.springframework.beans.factory.config.MethodInvokingFactoryBean。例如:

public class AESEncryptor {
    private static String password;

    static void setPassword(String newPass) {
        password = newPass;
    }
}

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod" value="sample.AESEncryptor.setPassword"/>
    <property name="arguments">
        <list>
            <value>secret</value>
        </list>
   </property>
</bean>

要将此功能与配置文件集成,您可以选择多种选项。最简单的方法就是将MethodInvokingFactoryBean定义与概要定义一起包装。例如:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <beans profile="dev">
        <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
            <property name="staticMethod" value="sample.AESEncryptor.setPassword"/>
            <property name="arguments">
                <list>
                    <value>secretForDev</value>
                </list>
           </property>
        </bean>
    </beans>

    <beans profile="stage">
        <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
            <property name="staticMethod" value="sample.AESEncryptor.setPassword"/>
            <property name="arguments">
                <list>
                    <value>secretForStage</value>
                </list>
           </property>
        </bean>
    </beans>

    <beans profile="prod">
        <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
            <property name="staticMethod" value="sample.AESEncryptor.setPassword"/>
            <property name="arguments">
                <list>
                    <value>secretForProd</value>
                </list>
           </property>
        </bean>
    </beans>
</beans>

然后,您可以通过设置spring.profiles.active系统属性来激活配置文件。

但是,使用更简单的方法可能会更好。来自Spring blog

  

如果更简单的方法可以完成工作,请不要使用配置文件。如果   只有在配置文件之间更改的是属性的值,   Spring现有的PropertyPlaceholderConfigurer /    可能就是你所需要的一切。

为此,您可以使用类似于以下内容的配置:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod" value="sample.AESEncryptor.setPassword"/>
    <property name="arguments">
        <list>
            <value>${security.encrypt.secret}</value>
        </list>
   </property>
</bean>

<util:properties location="classpath:environment.properties"/>

然后,您将拥有一个 environment.properties 文件,该文件包含在每个环境的类路径中。 dev的示例可能如下所示:

security.encrypt.secret=secretForDev