我们正在使用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并且几乎总是不鼓励。此外,我们不确定这是否可能无法解决垃圾收集问题。
怎么可能/应该这样做?
答案 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