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环境作用域),使用外部属性文件
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- Map-making Robots: A Review of the Occupancy Grid Map Algorithm
栅格地图算法:http://www.ikaros-project.org/articles/2008/gridmaps/
- tensor 维度 问题。
tf.argmax takes two arguments: input and dimension. example: tf.argmx(arr, dimension = 1). or tf.arg ...
- CLR VIA C# 泛型的协变和逆变
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Oracle——创建和管理表
一.常见的数据库对象 对象 描述 表 基本的数据存储集合,由行和列组成 视图 从表中抽出的逻辑上相关的数据集合 序列 提供有规律的数值 索引 提高查询的效率 同以词 给对象起别名 二.Oracle 数 ...
- 认识Filter
1). Filter 是什么 ? ①. JavaWEB 的一个重要组件, 可以对发送到 Servlet 的请求进行拦截, 并对响应也进行拦截. ②. Filter 是实现了 Filter 接口的 Ja ...
- HDU 4081 Peach Blossom Spring (最小生成树+dfs)
题意:给定一个 n 个点和相应的权值,要求你用 n-1 条边连接起来,其中一条边是魔法边,不用任何费用,其他的边是长度,求该魔法边的两端的权值与其他边费用的尽量大. 析:先求出最小生成树,然后再枚举每 ...
- JAVA自动装箱拆箱与常量池
java 自动装箱与拆箱 这个是jdk1.5以后才引入的新的内容,作为秉承发表是最好的记忆,毅然决定还是用一篇博客来代替我的记忆: java语言规范中说道:在许多情况下包装与解包装是由编译器自行完成的 ...
- Tomcat与Web.xml配置
1.编码配置 <Connector acceptCount=”100″ connectionTimeout=”20000″ disableUploadTimeout=”true” enableL ...
- 小度wifi在window server2008R2系统下创建不了
小度wifi在window server2008R2系统下创建的时候会一直显示正在创建,然后又消失的情况.这是因为win server 2008下默认的无线lan服务没开启 解决方法: 在“服务管理器 ...
- 【SQL】- 基础知识梳理(七) - 索引
索引的概念 在关系型数据库中,索引是对数据库表中一列或多列的值进行排序的一种结构. SQL SERVER中有索引的类型:按存储结构区分:“聚集索引(又称聚类索引,簇集索引)”,“分聚集索引(非聚类索引 ...