Spring中扩展 PropertyPlaceholderConfigurer处理加密属性文件
2014-01-07 10:53
495 查看
当我们在项目中配置数据源时,经常会将其对应的一些属性值写到另外的属性文件中,这样的好处是可以简化项目维护和部署工作,当项目从开发环境迁移到生产环境的时候,运维人员只需要修改数据源对应的属性文件就可以了,无需关注其他的配置文件。如果在属性文件中将数据库的用户名和密码等敏感信息以明文的方式写在文件中,这是非常不安全的,所以我们就需要将属性文件中的部分信息进行加密处理以提高安全性。下面介绍如何运用spring中的PropertyPlaceholderConfigurer类对加密的属性值进行处理。
假设数据源配置信息放在jdbc.properties文件中,如果对属性文件不需要做任何处理则可以利用context命名空间定义属性文件:
[html]
view plaincopyprint?
<context:property-placeholder location="classpath:jdbc.properties"/>
PropertyPlaceholderConfigurer类本身对加密的数据不做任何处理的,所以我们需要自定义类继承PropertyPlaceholderConfigurer,并且重写父类中的方法。通过spring源码我们可以看到PropertyPlaceholderConfigurer类uml图如下所示。
图(1)
PropertyResourceConfigurer类实现BeanFactoryPostProcessor接口是一个后置处理器类,找到postProcessBeanFactory方法发现跟获取属性值有关的方法为convertProperties方法,源码如下所示:
[java]
view plaincopyprint?
protected void convertProperties(Properties props) { for(Enumeration propertyNames = props.propertyNames(); propertyNames.hasMoreElements();){ String propertyName = (String) propertyNames.nextElement(); String propertyValue = props.getProperty(propertyName); String convertedValue = convertProperty(propertyName, propertyValue); if(!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) props.setProperty(propertyName, convertedValue); } } protected String convertProperty(String propertyName,String propertyValue) { return convertPropertyValue(propertyValue); } protected String convertPropertyValue(String originalValue) { return originalValue; }
看到这里我们就可以清楚的知道spring是通过该类中的convertProperty方法返回对应属性名处理后的属性值的,convertProperty方法中调用了convertPropertyValue方法用于返回属性值,所以如果我们要对属性文件中的所有属性值进行解密处理,就只需重写convertPropertyValue方法, 这里我们只需针对指定的属性名做解密处理,所以在子类中重写convertProperty方法就可以了,子类代码如下所示:
[java]
view plaincopyprint?
package com.yao.cs.common.config;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import com.yao.cs.common.utils.DesUtils;
public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer{
/**
* 重写父类方法,解密指定属性名对应的属性值
*/
@Override
protected String convertProperty(String propertyName,String propertyValue){
if(isEncryptPropertyVal(propertyName)){
return DesUtils.getDecryptString(propertyValue);//调用解密方法
}else{
return propertyValue;
}
}
/**
* 判断属性值是否需要解密,这里我约定需要解密的属性名用encrypt开头
* @param propertyName
* @return
*/
private boolean isEncryptPropertyVal(String propertyName){
if(propertyName.startsWith("encrypt")){
return true;
}else{
return false;
}
}
}
在spring容器中定义DecryptPropertyPlaceholderConfigurerbean,并且指定属性文件,如下所示:
[html]
view plaincopyprint?
<bean class="com.nankang.cs.common.config.DecryptPropertyPlaceholderConfigurer" p:location="classpath:jdbc.properties"/>
jdbc.properties属性文件中的描述如下(需要解密的属性名约定以encrypt开头):
[plain]
view plaincopyprint?
encrypt_user=HSyMvmpqUdE\=
encrypt_pwd=K/5gIGiWG+12csSxj8AINw==
数据源如下配置:
[html]
view plaincopyprint?
<bean id="firstDataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close"
p:driverClassName="${driverClassName}"
p:url="${jdbcUrl}"
p:username="${encrypt_user}"
p:password="${encrypt_pwd}"
p:initialSize="${initialSize}"
p:maxActive="${maxActive}"
p:minIdle="${minIdle}"
p:poolPreparedStatements="${poolPreparedStatements}"
p:testOnBorrow="${testOnBorrow}"/>
这里我用了阿里的Druid数据源,虽然Druid数据源可以通过connectProperties和passwordCallback两个参数对属性值进行加密处理,但是项目中用到了spring,以上含有占位符的bean对于spring来说就是一个半成品的bean,还需要用实现BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法进行处理,所以在spring项目中将加密的属性值交给spring处理会比较好。
假设数据源配置信息放在jdbc.properties文件中,如果对属性文件不需要做任何处理则可以利用context命名空间定义属性文件:
[html]
view plaincopyprint?
<context:property-placeholder location="classpath:jdbc.properties"/>
<context:property-placeholder location="classpath:jdbc.properties"/>
PropertyPlaceholderConfigurer类本身对加密的数据不做任何处理的,所以我们需要自定义类继承PropertyPlaceholderConfigurer,并且重写父类中的方法。通过spring源码我们可以看到PropertyPlaceholderConfigurer类uml图如下所示。
图(1)
PropertyResourceConfigurer类实现BeanFactoryPostProcessor接口是一个后置处理器类,找到postProcessBeanFactory方法发现跟获取属性值有关的方法为convertProperties方法,源码如下所示:
[java]
view plaincopyprint?
protected void convertProperties(Properties props) { for(Enumeration propertyNames = props.propertyNames(); propertyNames.hasMoreElements();){ String propertyName = (String) propertyNames.nextElement(); String propertyValue = props.getProperty(propertyName); String convertedValue = convertProperty(propertyName, propertyValue); if(!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) props.setProperty(propertyName, convertedValue); } } protected String convertProperty(String propertyName,String propertyValue) { return convertPropertyValue(propertyValue); } protected String convertPropertyValue(String originalValue) { return originalValue; }
protected void convertProperties(Properties props) { for(Enumeration propertyNames = props.propertyNames(); propertyNames.hasMoreElements();){ String propertyName = (String) propertyNames.nextElement(); String propertyValue = props.getProperty(propertyName); String convertedValue = convertProperty(propertyName, propertyValue); if(!ObjectUtils.nullSafeEquals(propertyValue, convertedValue)) props.setProperty(propertyName, convertedValue); } } protected String convertProperty(String propertyName,String propertyValue) { return convertPropertyValue(propertyValue); } protected String convertPropertyValue(String originalValue) { return originalValue; }
看到这里我们就可以清楚的知道spring是通过该类中的convertProperty方法返回对应属性名处理后的属性值的,convertProperty方法中调用了convertPropertyValue方法用于返回属性值,所以如果我们要对属性文件中的所有属性值进行解密处理,就只需重写convertPropertyValue方法, 这里我们只需针对指定的属性名做解密处理,所以在子类中重写convertProperty方法就可以了,子类代码如下所示:
[java]
view plaincopyprint?
package com.yao.cs.common.config;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import com.yao.cs.common.utils.DesUtils;
public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer{
/**
* 重写父类方法,解密指定属性名对应的属性值
*/
@Override
protected String convertProperty(String propertyName,String propertyValue){
if(isEncryptPropertyVal(propertyName)){
return DesUtils.getDecryptString(propertyValue);//调用解密方法
}else{
return propertyValue;
}
}
/**
* 判断属性值是否需要解密,这里我约定需要解密的属性名用encrypt开头
* @param propertyName
* @return
*/
private boolean isEncryptPropertyVal(String propertyName){
if(propertyName.startsWith("encrypt")){
return true;
}else{
return false;
}
}
}
package com.yao.cs.common.config; import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; import com.yao.cs.common.utils.DesUtils; public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer{ /** * 重写父类方法,解密指定属性名对应的属性值 */ @Override protected String convertProperty(String propertyName,String propertyValue){ if(isEncryptPropertyVal(propertyName)){ return DesUtils.getDecryptString(propertyValue);//调用解密方法 }else{ return propertyValue; } } /** * 判断属性值是否需要解密,这里我约定需要解密的属性名用encrypt开头 * @param propertyName * @return */ private boolean isEncryptPropertyVal(String propertyName){ if(propertyName.startsWith("encrypt")){ return true; }else{ return false; } } }
在spring容器中定义DecryptPropertyPlaceholderConfigurerbean,并且指定属性文件,如下所示:
[html]
view plaincopyprint?
<bean class="com.nankang.cs.common.config.DecryptPropertyPlaceholderConfigurer" p:location="classpath:jdbc.properties"/>
<bean class="com.nankang.cs.common.config.DecryptPropertyPlaceholderConfigurer" p:location="classpath:jdbc.properties"/>
jdbc.properties属性文件中的描述如下(需要解密的属性名约定以encrypt开头):
[plain]
view plaincopyprint?
encrypt_user=HSyMvmpqUdE\=
encrypt_pwd=K/5gIGiWG+12csSxj8AINw==
encrypt_user=HSyMvmpqUdE\= encrypt_pwd=K/5gIGiWG+12csSxj8AINw==
数据源如下配置:
[html]
view plaincopyprint?
<bean id="firstDataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close"
p:driverClassName="${driverClassName}"
p:url="${jdbcUrl}"
p:username="${encrypt_user}"
p:password="${encrypt_pwd}"
p:initialSize="${initialSize}"
p:maxActive="${maxActive}"
p:minIdle="${minIdle}"
p:poolPreparedStatements="${poolPreparedStatements}"
p:testOnBorrow="${testOnBorrow}"/>
<bean id="firstDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close" p:driverClassName="${driverClassName}" p:url="${jdbcUrl}" p:username="${encrypt_user}" p:password="${encrypt_pwd}" p:initialSize="${initialSize}" p:maxActive="${maxActive}" p:minIdle="${minIdle}" p:poolPreparedStatements="${poolPreparedStatements}" p:testOnBorrow="${testOnBorrow}"/>
这里我用了阿里的Druid数据源,虽然Druid数据源可以通过connectProperties和passwordCallback两个参数对属性值进行加密处理,但是项目中用到了spring,以上含有占位符的bean对于spring来说就是一个半成品的bean,还需要用实现BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法进行处理,所以在spring项目中将加密的属性值交给spring处理会比较好。
相关文章推荐
- Spring中扩展 PropertyPlaceholderConfigurer处理加密属性文件
- Spring中扩展 PropertyPlaceholderConfigurer处理加密属性文件
- Spring中扩展 PropertyPlaceholderConfigurer处理加密属性文件
- 扩展PropertyPlaceholderConfigurer对prop文件中的属性加密
- Spring代码实例系列-09:通过Spring PropertyPlaceholderConfigurer将properties配置的属性注入到xml配置文件中
- Spring学习笔记 通过PropertyPlaceholderConfigurer来使用properties文件初始化Map类型属性
- Spring PropertyPlaceholderConfigurer获取属性文件值
- spring管理属性配置文件properties——使用PropertyPlaceholderConfigurer
- spring里PropertyPlaceholderConfigurer读取属性文件
- Spring —— web.xml 中用 PropertyPlaceholderConfigurer 类读取properties 文件 或 属性
- 【转】spring管理属性配置文件properties——使用PropertiesFactoryBean|spring管理属性配置文件properties——使用PropertyPlaceholderConfigurer
- Spring环境搭建之:通过PropertyPlaceholderConfigurer加载属性配置文件:
- spring管理属性配置文件properties——PropertiesFactoryBean和PropertyPlaceholderConfigurer的区别
- spring中使用外部属性文件(关于PropertyPlaceholderConfigurer)
- PropertyPlaceholderConfigurer在spring获取属性文件
- Spring PropertyPlaceholderConfigurer解析Java Properties属性文件值
- 使用外部属性文件(关于PropertyPlaceholderConfigurer)
- Spring PropertyPlaceholderConfigurer Usage - 使用系统变量替换spring配置文件中的变量
- spring+mybatis使用MapperScannerConfigurer引起的PropertyPlaceholderConfigurer无效问题处理方法
- spring使用PropertyPlaceholderConfigurer扩展来满足不同环境的参数配置