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环境作用域),使用外部属性文件
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- JMS-消息中间件的应用02-安装ActiveMQ-来自慕课学习-新手学习
What is ActiveMQ? -----突然好想打英文,好奇怪 请看来自官网的介绍: Apache ActiveMQ ™ is the most popular and powerf ...
- 如何快速搭建基于python+appium的自动化测试环境
首先申明本文是基本于Python与Android来快速搭建Appium自动化测试环境: 主要分为以下几个步骤: 前提条件: 1)安装与配置python环境,打开 Python官网,找到“Downloa ...
- 状态压缩DP----HDU2809
状态压缩DP的一道较不错的入门题,第二次做这类问题,感觉不是很顺手,故记录下来. 题目的意思就是吕布战群雄,先给你6个数,分别是吕布的攻击值,防御值,生命值,升级后此三值各自的增量,然后是对手的个数n ...
- POJ3020 Antenna Placement(二分图最小路径覆盖)
The Global Aerial Research Centre has been allotted the task of building the fifth generation of mob ...
- 图的遍历——BFS
原创 裸一篇图的BFS遍历,直接来图: 简单介绍一下BFS遍历的过程: 以上图为例子,从0开始遍历,访问0,按大小顺序访问与0相邻的所有顶点,即先访问1,再访问2: 至此顶点0已经没有作用了,因为其本 ...
- postfix 安装配置详解
[ref: http://blog.51yip.com/server/1382.html] [http://blog.chinaunix.net/uid-174325-id-1744019.html] ...
- C#字符串string的常用使用方法(转载)
1--->字符串的声明: 1.string s=new string(char[] arr) //根据一个字符数组声明字符串,即将字符字组转化为字符串. 2.string s=new s ...
- Android ViewPager + Fragment的布局
ViewPager And Fragment 1.之前有篇博客是讲ViewPager的用法的:http://www.cnblogs.com/liangstudyhome/p/3773156.html ...
- [译] 关于 SPA,你需要掌握的 4 层 (2)
此文已由作者张威授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 视图层 现在我们有了一个可执行且不依赖于框架的应用程序,React 已经准备投入使用. 视图层由 presen ...
- CENTOS7 使用 Nginx + Uwsgi 部署 Django 项目
写在前面的话 最近总是见到有新学 Django 的朋友在部署自己的项目到 Linux 上面的时候运行不起来,所以就动手写了这篇博客. 对于不会搭建 Python 3 环境的朋友可以参考前面的博客[CE ...