Spring对外部属性文件指定的某个属性进行加密、解密
[From] http://blog.csdn.net/ethanq/article/details/7333897
在我们开发当中,经常会用到spring框架来读取属性文件的属性值,然后使用占位符引用属性文件的属性值来简化配置以及使配置具有更高的灵活性和通用性。
如下面的属性配置文件:db.properties
#数据库配置
db.driver=org.postgresql.Driver
db.url=jdbc\:postgresql\://10.166.176.127\:5432/test
db.username=ivsadmin
db.password=123456
db.name=ivs
applicationContext.xml文件
- <context:property-placeholder location="classpath:db.properties" />
- <bean id="dataSource"
- class="com.mchange.v2.c3p0.ComboPooledDataSource"
- destroy-method="close">
- <property name="driverClass" value="${db.driver}" />
- <property name="jdbcUrl" value="${db.url}" />
- <property name="user" value="${db.username}" />
- <property name="password" value="${db.password}" />
- <property name="checkoutTimeout" value="3000" />
- </bean>
对于一些敏感的属性值,例如:密码属性。为了达到安全目的,我们一般会将密码进行加密。
可能希望用户看到db.properties是这样的:
#数据库配置
db.driver=org.postgresql.Driver
db.url=jdbc\:postgresql\://10.166.176.127\:5432/ivs
db.username=ivsadmin
db.password={SMC}sYNzVKgIhOprkdGhCyt81w==
db.name=ivs
这里可以看到密码属性值是加密过的,其它的属性值不变,这样就达到安全目的。这里采用的是java的3DES加密,在前面的文章中 3DES加密、解密工具类 已经有介绍了
下面开始分析下我们的需求:
在Spring中担负对外在化应用参数的配置的是PropertyPlaceholderConfigurer和PropertyOverrideConfigurer对象,PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor接口,它能够对<bean/>中的属性值进行外在化管理。
就像这样:
- <bean id="propertyConfigurer1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <value>WEB-INF/classes/db.properties</value>
- </property>
- </bean>
为简化PropertyPlaceholderConfigurer的使用,Spring提供了<context:property-placeholder/>元素,像applicationContext.xml文件中这样:<context:property-placeholder
location="classpath:db.properties" />
这里就很清楚了,我们只要继承PropertyPlaceholderConfigurer对象,重写PropertiesLoaderSupport接口的loadProperties方法,就可以对外部属性文件的属性值进行相关的操作了
明白了需求,下来开始我们的实现代码:
DecryptPropertyPlaceholderConfigurer.java
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.util.Properties;
- import org.apache.commons.lang.StringUtils;
- import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
- import org.springframework.core.io.Resource;
- import com.huawei.smc.commons.constants.CommonContants;
- /**
- * <一句话功能简述>
- *
- * @author hKF44803
- * @version [版本号, 2011-12-6]
- * @see [相关类/方法]
- * @since [产品/模块版本]
- */
- public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer
- {
- private Resource[] locations;
- private DecryptPropertiesPersister propertiesPersister = new DecryptPropertiesPersister();
- private String fileEncoding = "utf-8";
- private boolean ignoreResourceNotFound = false;
- /**
- * {@inheritDoc}
- */
- @Override
- public void setLocations(Resource[] locations)
- {
- this.locations = locations;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void setFileEncoding(String encoding)
- {
- this.fileEncoding = encoding;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void setIgnoreResourceNotFound(boolean ignoreResourceNotFound)
- {
- this.ignoreResourceNotFound = ignoreResourceNotFound;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- public void loadProperties(Properties props)
- throws IOException
- {
- // 属性文件是否为空
- if (this.locations != null)
- {
- // 循环读取属性文件
- for (int i = 0; i < this.locations.length; i++)
- {
- Resource location = this.locations[i];
- InputStream is = null;
- FileOutputStream fos = null;
- try
- {
- is = location.getInputStream();
- // 检查文件是否是XML文件
- if (location.getFilename().endsWith(XML_FILE_EXTENSION))
- {
- this.propertiesPersister.loadFromXml(props, is);
- }
- // 属性文件
- else
- {
- this.propertiesPersister.doLoad(props, new InputStreamReader(is, this.fileEncoding));
- String content = this.propertiesPersister.getEncryptContent();
- // 查找是否存在加密标识
- if (StringUtils.contains(content, CommonContants.DECRYPT_FLAG))
- {
- try
- {
- File file = location.getFile();
- fos = new FileOutputStream(file);
- fos.write(this.propertiesPersister.getEncryptContent().getBytes());
- fos.flush();
- }
- finally
- {
- if (null != fos)
- {
- fos.close();
- }
- }
- }
- }
- }
- catch (IOException ex)
- {
- if (this.ignoreResourceNotFound)
- {
- if (logger.isWarnEnabled())
- {
- logger.warn("Could not load properties from " + location + ": " + ex.getMessage());
- }
- }
- else
- {
- throw ex;
- }
- }
- finally
- {
- if (is != null)
- {
- is.close();
- }
- }
- }
- }
- }
- }
其中propertiesPersister变量用我们写的DefaultPropertiesPersister类来实现,DecryptPropertiesPersister.java对象
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.Reader;
- import java.util.Properties;
- import org.springframework.util.DefaultPropertiesPersister;
- import org.springframework.util.StringUtils;
- import com.huawei.smc.commons.constants.CommonContants;
- import com.huawei.smc.commons.constants.NumberConstants;
- import com.huawei.smc.commons.util.ThreeDesUtil;
- /**
- * 重载DefaultPropertiesPersister类
- *
- * @author hKF44803
- * @version [版本号, 2011-12-6]
- * @see [相关类/方法]
- * @since [产品/模块版本]
- */
- public class DecryptPropertiesPersister extends DefaultPropertiesPersister
- {
- // 加密后的字符串
- private String encryptContent;
- public String getEncryptContent()
- {
- return encryptContent;
- }
- /**
- * {@inheritDoc}
- */
- @Override
- protected void doLoad(Properties props, Reader reader)
- throws IOException
- {
- BufferedReader in = new BufferedReader(reader);
- // 最后写入的内容
- StringBuilder sbContent = new StringBuilder();
- // 循环读取文件
- while (true)
- {
- // 读取每一行
- String line = in.readLine();
- // 非空检查
- if (line == null)
- {
- break;
- }
- // 去掉空格
- line = StringUtils.trimLeadingWhitespace(line);
- // 读取行为空,跳出循环
- if (line.length() == 0)
- {
- // 长度为0,换行
- sbContent.append("\n");
- continue;
- }
- // 每行的第一个字符
- char firstChar = line.charAt(0);
- // 第一个字符不是#和!
- if (firstChar != '#' && firstChar != '!')
- {
- while (endsWithContinuationMarker(line))
- {
- String nextLine = in.readLine();
- line = line.substring(0, line.length() - 1);
- // 非空检查
- if (nextLine != null)
- {
- line += StringUtils.trimLeadingWhitespace(nextLine);
- }
- }
- // 查找等号所有位置的索引
- int separatorIndex = line.indexOf("=");
- // 没有等号
- if (separatorIndex == -1)
- {
- separatorIndex = line.indexOf(":");
- }
- // 取KEY
- String key = (separatorIndex != -1) ? line.substring(0, separatorIndex) : line;
- // 取KEY的值
- String value = (separatorIndex != -1) ? line.substring(separatorIndex + 1) : "";
- // 去掉空格
- key = StringUtils.trimTrailingWhitespace(key);
- value = StringUtils.trimLeadingWhitespace(value);
- // 将所有的属性放到持久的属性集*
- props.put(unescape(key), unescape(value));
- // DB属性文件
- if (CommonContants.DB_PASSWORD_PROPS.equals(key))
- {
- // 实例加密工具类
- ThreeDesUtil desUtil = new ThreeDesUtil();
- // DB密码解密
- if (value.startsWith(CommonContants.DECRYPT_FLAG))
- {
- // 去掉标识
- value = value.substring(NumberConstants.INT_5);
- // 对加密的属性进行3DES解密
- value = desUtil.decrypt(value);
- // 解密的值放到props中
- props.put(unescape(key), unescape(value));
- }
- // DB密码加密
- else
- {
- // 加密指定的值
- String strEncrypt = desUtil.encrypt(value);
- // 加密后的值添加一个标识,区分解密、加密
- value = CommonContants.DECRYPT_FLAG + strEncrypt;
- // 加密后的行
- line = key + CommonContants.PROPERTIES_SEPERATE + value;
- sbContent.append(line + "\n");
- }
- }
- // 追加其它的属性
- else
- {
- sbContent.append(line + "\n");
- }
- }
- else
- {
- // 追加读取的注释内容
- sbContent.append(line + "\n");
- }
- }
- encryptContent = sbContent.toString();
- }
- }
最后需要修改下applicationContext.xml文件,如下:
- <bean id="propertyConfigurer1" class="com.huawei.smc.commons.DecryptPropertyPlaceholderConfigurer">
- <property name="locations">
- <value>WEB-INF/classes/db.properties</value>
- </property>
- </bean>
- <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
- <property name="driverClass" value="${db.driver}" />
- <property name="jdbcUrl" value="${db.url}" />
- <property name="user" value="${db.username}" />
- <property name="password" value="${db.password}" />
- <property name="checkoutTimeout" value="3000" />
- </bean>

这样对属性的加密就完成了,Spring进行加载的完成后,属性就加密了
提示:如果在配置中有多个配置文件需要加载,并且这些属性文件不需要做任何处理,那就需要添加下面的配置:
- <bean id="propertyConfigurer"
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="order" value="1" />
- <property name="ignoreUnresolvablePlaceholders" value="true" />
- <property name="locations">
- <value>WEB-INF/classes/smc.properties</value>
- </property>
Spring对外部属性文件指定的某个属性进行加密、解密的更多相关文章
- Java - 得到项目中properties属性文件中定义的属性值
public static String getPropertiesValue(String fileName, String key) { return ResourceBundle.getBu ...
- Java属性中指定Json的属性名称
只需要使用注解"@JsonProperty(value = "pwd")" import com.fasterxml.jackson.annotation.Js ...
- 属性文件——Java&Spring
属性文件 什么是属性文件 ? 定义:一个扩展名为properties文件,属性文件都是以key-value(键值对)来保存文件的内容,如:log4j.properties,db.properties等 ...
- 十八 Spring的JDBC模板:引入外部属性文件
配置外部属性文件 配置文件里引入属性文件,两种方式 第一种: 第二种: 引入属性文件的值: 测试: <?xml version="1.0" encoding="UT ...
- java解析属性文件
-----------------------解析属性文件----------------------------- /** * 获取src下属性文件 * @param params * ...
- Java操作属性文件,支持新增或更新多个属性
Java操作属性文件.支持新增或更新多个属性 一.更新或新增单个属性的方法 /** * 写入properties信息 * @param filePath 绝对路径(包含文件名称和后缀名) * @par ...
- java:Properties属性文件概念
java:Properties属性文件概念 在java之前的国际化程序中提出了一个属性文件的概念,属性文件的后缀是:*.properties,那么在java中提供了意个属性文件的专门操作类,Prope ...
- Java AES加密解密工具 -- GUI 、在线传输文件
原理 对于任意长度的明文,AES首先对其进行分组,每组的长度为128位.分组之后将分别对每个128位的明文分组进行加密. 对于每个128位长度的明文分组的加密过程如下: (1)将128位AES ...
- [原创]java WEB学习笔记99:Spring学习---Spring Bean配置:自动装配,配置bean之间的关系(继承/依赖),bean的作用域(singleton,prototype,web环境作用域),使用外部属性文件
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- DBMS ODBC JDBC是什么?
昨天躺在被窝里面看了几页电子书,今天写下来. 数据库就是存放数据的仓库. DBMS的意思是数据库管理系统,作用就是“管理”数据库的.“管理”这两个字简单说来就是“增删改查”.所以DBMS就是能够对数据 ...
- 修改laravel中的pagination的样式
运行如下命令,拷贝出pagination样式到public/vendor目录下, 然后在pagination实例上调用links(‘传路径’)方法 使用起来非常方便,同时也可以自定义样式
- 利用 Aspose.Words 组件,在不依赖与 Office 组件的情况下把 Word 文件转换成 HTML 代码。
首先利用 Nuget 获取 Aspose.Words.dll public ActionResult AsposeWordsDemo() { string srcFileName = Server.M ...
- Qt工程文件Pro介绍(转)
转载请注明:http://blog.163.com/hu_cuit/blog/static/122849143201127104232142/ 我也才开始学习QT的菜鸟.但是前几天有同学叫我给他讲一下 ...
- HttpUploader6.2-process版本
1.优化JS逻辑,在上传前先同步相同文件进度,提高多用户上传效率. 2.优化文件块保存逻辑,减少相同文件块的写入操作,减少服务器IO操作,提高上传效率. js变化: up6.js新增UrlQuer ...
- linux新的API signalfd、timerfd、eventfd使用说明
原文:http://www.cfanz.cn/?c=article&a=read&id=46555注意很多当前(2013/8/6)线上运营的Linux内核可能不支持! 三种新的fd加入 ...
- linux下SVN服务器配置
SVN服务器配置 1. 安装svn服务 yum install subversion 2. 新建一个目录用于存储SVN所有文件 mkdir /home/svn 3. 创建项目 在上面创建的文件夹中为项 ...
- attachEvent 与 addEventListener 的监听
说到 attachEvent 与 addEventListener 的事件必然会提到 浏览器的判断,因为attachEvent只适用于于IE 先来看看常用的浏览器的判断 //判断浏览器类型 if(n ...
- string Format转义大括号
String.Format("{0} world!","hello") //将输出 hello world!,没有问题,但是只要在第一个参数的任意位置加上一个大 ...
- .Net Mvc 四种过滤器
一.授权过滤器:AuthorizationFilters 二.动作过滤:ActionFilters 三.响应过滤:ResultFilters 四.异常过滤:ExceptionFilters ===== ...