Spring对外部属性文件指定的某个属性进行加密、解密

来源:互联网 发布:activemq amqp java 编辑:程序博客网 时间:2024/05/22 09:48

[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文件

[html] view plain copy
  1. <context:property-placeholder location="classpath:db.properties" />  
  2.    
  3.    <bean id="dataSource"  
  4. class="com.mchange.v2.c3p0.ComboPooledDataSource"  
  5. destroy-method="close">  
  6. <property name="driverClass" value="${db.driver}" />  
  7. <property name="jdbcUrl" value="${db.url}" />  
  8. <property name="user" value="${db.username}" />  
  9. <property name="password" value="${db.password}" />  
  10. <property name="checkoutTimeout" value="3000" />  
  11.    </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/>中的属性值进行外在化管理。
  就像这样:

[html] view plain copy
  1. <bean id="propertyConfigurer1" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  2. <property name="locations">  
  3.     <value>WEB-INF/classes/db.properties</value>  
  4. </property>  
  5.   </bean>  

为简化PropertyPlaceholderConfigurer的使用,Spring提供了<context:property-placeholder/>元素,像applicationContext.xml文件中这样:<context:property-placeholder location="classpath:db.properties" />
这里就很清楚了,我们只要继承PropertyPlaceholderConfigurer对象,重写PropertiesLoaderSupport接口的loadProperties方法,就可以对外部属性文件的属性值进行相关的操作了

明白了需求,下来开始我们的实现代码:

DecryptPropertyPlaceholderConfigurer.java

[java] view plain copy
  1. import java.io.File;  
  2. import java.io.FileOutputStream;  
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.InputStreamReader;  
  6. import java.util.Properties;  
  7.    
  8. import org.apache.commons.lang.StringUtils;  
  9. import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;  
  10. import org.springframework.core.io.Resource;  
  11.    
  12. import com.huawei.smc.commons.constants.CommonContants;  
  13.    
  14. /** 
  15.  * <一句话功能简述> 
  16.  *  
  17.  * @author  hKF44803 
  18.  * @version  [版本号, 2011-12-6] 
  19.  * @see  [相关类/方法] 
  20.  * @since  [产品/模块版本] 
  21.  */  
  22. public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer  
  23. {  
  24.     private Resource[] locations;  
  25.        
  26.     private DecryptPropertiesPersister propertiesPersister = new DecryptPropertiesPersister();  
  27.        
  28.     private String fileEncoding = "utf-8";  
  29.        
  30.     private boolean ignoreResourceNotFound = false;  
  31.        
  32.     /** 
  33.      * {@inheritDoc} 
  34.      */  
  35.     @Override  
  36.     public void setLocations(Resource[] locations)  
  37.     {  
  38.         this.locations = locations;  
  39.     }  
  40.        
  41.     /** 
  42.      * {@inheritDoc} 
  43.      */  
  44.     @Override  
  45.     public void setFileEncoding(String encoding)  
  46.     {  
  47.         this.fileEncoding = encoding;  
  48.     }  
  49.        
  50.     /** 
  51.      * {@inheritDoc} 
  52.      */  
  53.     @Override  
  54.     public void setIgnoreResourceNotFound(boolean ignoreResourceNotFound)  
  55.     {  
  56.         this.ignoreResourceNotFound = ignoreResourceNotFound;  
  57.     }  
  58.        
  59.     /** 
  60.      * {@inheritDoc} 
  61.      */  
  62.     @Override  
  63.     public void loadProperties(Properties props)  
  64.         throws IOException  
  65.     {  
  66.            
  67.         // 属性文件是否为空  
  68.         if (this.locations != null)  
  69.         {  
  70.             // 循环读取属性文件  
  71.             for (int i = 0; i < this.locations.length; i++)  
  72.             {  
  73.                 Resource location = this.locations[i];  
  74.                    
  75.                 InputStream is = null;  
  76.                 FileOutputStream fos = null;  
  77.                 try  
  78.                 {  
  79.                        
  80.                     is = location.getInputStream();  
  81.                        
  82.                     // 检查文件是否是XML文件  
  83.                     if (location.getFilename().endsWith(XML_FILE_EXTENSION))  
  84.                     {  
  85.                         this.propertiesPersister.loadFromXml(props, is);  
  86.                     }  
  87.                    // 属性文件  
  88.                     else  
  89.                     {  
  90.                         this.propertiesPersister.doLoad(props, new InputStreamReader(is, this.fileEncoding));  
  91.                         String content = this.propertiesPersister.getEncryptContent();  
  92.                            
  93.                         // 查找是否存在加密标识  
  94.                         if (StringUtils.contains(content, CommonContants.DECRYPT_FLAG))  
  95.                         {  
  96.                             try  
  97.                             {  
  98.                                 File file = location.getFile();  
  99.                                    
  100.                                 fos = new FileOutputStream(file);  
  101.                                    
  102.                                 fos.write(this.propertiesPersister.getEncryptContent().getBytes());  
  103.                                 fos.flush();  
  104.                                    
  105.                             }  
  106.                             finally  
  107.                             {  
  108.                                 if (null != fos)  
  109.                                 {  
  110.                                     fos.close();  
  111.                                 }  
  112.                             }  
  113.                         }  
  114.                     }  
  115.                 }  
  116.                 catch (IOException ex)  
  117.                 {  
  118.                     if (this.ignoreResourceNotFound)  
  119.                     {  
  120.                         if (logger.isWarnEnabled())  
  121.                         {  
  122.                             logger.warn("Could not load properties from " + location + ": " + ex.getMessage());  
  123.                         }  
  124.                     }  
  125.                     else  
  126.                     {  
  127.                         throw ex;  
  128.                     }  
  129.                 }  
  130.                 finally  
  131.                 {  
  132.                        
  133.                     if (is != null)  
  134.                     {  
  135.                         is.close();  
  136.                     }  
  137.                        
  138.                 }  
  139.             }  
  140.         }  
  141.     }  
  142. }  

其中propertiesPersister变量用我们写的DefaultPropertiesPersister类来实现,DecryptPropertiesPersister.java对象

[java] view plain copy
  1. import java.io.BufferedReader;  
  2. import java.io.IOException;  
  3. import java.io.Reader;  
  4. import java.util.Properties;  
  5.    
  6. import org.springframework.util.DefaultPropertiesPersister;  
  7. import org.springframework.util.StringUtils;  
  8.    
  9. import com.huawei.smc.commons.constants.CommonContants;  
  10. import com.huawei.smc.commons.constants.NumberConstants;  
  11. import com.huawei.smc.commons.util.ThreeDesUtil;  
  12.    
  13. /** 
  14.  * 重载DefaultPropertiesPersister类 
  15.  *  
  16.  * @author  hKF44803 
  17.  * @version  [版本号, 2011-12-6] 
  18.  * @see  [相关类/方法] 
  19.  * @since  [产品/模块版本] 
  20.  */  
  21. public class DecryptPropertiesPersister extends DefaultPropertiesPersister  
  22. {  
  23.     // 加密后的字符串  
  24.     private String encryptContent;  
  25.        
  26.     public String getEncryptContent()  
  27.     {  
  28.         return encryptContent;  
  29.     }  
  30.        
  31.     /** 
  32.      * {@inheritDoc} 
  33.      */  
  34.     @Override  
  35.     protected void doLoad(Properties props, Reader reader)  
  36.         throws IOException  
  37.     {  
  38.         BufferedReader in = new BufferedReader(reader);  
  39.            
  40.         // 最后写入的内容  
  41.         StringBuilder sbContent = new StringBuilder();  
  42.            
  43.         // 循环读取文件  
  44.         while (true)  
  45.         {  
  46.             // 读取每一行  
  47.             String line = in.readLine();  
  48.                
  49.             // 非空检查  
  50.             if (line == null)  
  51.             {  
  52.                 break;  
  53.             }  
  54.                
  55.             // 去掉空格  
  56.             line = StringUtils.trimLeadingWhitespace(line);  
  57.                
  58.             // 读取行为空,跳出循环  
  59.             if (line.length() == 0)  
  60.             {  
  61.                 // 长度为0,换行  
  62.                 sbContent.append("\n");  
  63.                    
  64.                 continue;  
  65.             }  
  66.                
  67.             // 每行的第一个字符  
  68.             char firstChar = line.charAt(0);  
  69.                
  70.             // 第一个字符不是#和!  
  71.             if (firstChar != '#' && firstChar != '!')  
  72.             {  
  73.                 while (endsWithContinuationMarker(line))  
  74.                 {  
  75.                     String nextLine = in.readLine();  
  76.                     line = line.substring(0, line.length() - 1);  
  77.                        
  78.                     // 非空检查  
  79.                     if (nextLine != null)  
  80.                     {  
  81.                         line += StringUtils.trimLeadingWhitespace(nextLine);  
  82.                     }  
  83.                 }  
  84.                    
  85.                 // 查找等号所有位置的索引  
  86.                 int separatorIndex = line.indexOf("=");  
  87.                    
  88.                 // 没有等号  
  89.                 if (separatorIndex == -1)  
  90.                 {  
  91.                     separatorIndex = line.indexOf(":");  
  92.                 }  
  93.                    
  94.                 // 取KEY  
  95.                 String key = (separatorIndex != -1) ? line.substring(0, separatorIndex) : line;  
  96.                    
  97.                 // 取KEY的值  
  98.                 String value = (separatorIndex != -1) ? line.substring(separatorIndex + 1) : "";  
  99.                    
  100.                 // 去掉空格  
  101.                 key = StringUtils.trimTrailingWhitespace(key);  
  102.                 value = StringUtils.trimLeadingWhitespace(value);  
  103.                    
  104.                 // 将所有的属性放到持久的属性集*  
  105.                 props.put(unescape(key), unescape(value));  
  106.                    
  107.   // DB属性文件  
  108.                 if (CommonContants.DB_PASSWORD_PROPS.equals(key))  
  109.                 {  
  110.                     // 实例加密工具类  
  111.                     ThreeDesUtil desUtil = new ThreeDesUtil();  
  112.                        
  113.                     // DB密码解密  
  114.                     if (value.startsWith(CommonContants.DECRYPT_FLAG))  
  115.                     {  
  116.                         // 去掉标识  
  117.                         value = value.substring(NumberConstants.INT_5);  
  118.                            
  119.                         // 对加密的属性进行3DES解密  
  120.                         value = desUtil.decrypt(value);  
  121.                            
  122.                         // 解密的值放到props中  
  123.                         props.put(unescape(key), unescape(value));  
  124.                     }  
  125.                     // DB密码加密  
  126.                     else  
  127.                     {  
  128.                         // 加密指定的值  
  129.                         String strEncrypt = desUtil.encrypt(value);  
  130.                            
  131.                         // 加密后的值添加一个标识,区分解密、加密  
  132.                         value = CommonContants.DECRYPT_FLAG + strEncrypt;  
  133.                            
  134.                         // 加密后的行  
  135.                         line = key + CommonContants.PROPERTIES_SEPERATE + value;  
  136.                            
  137.                         sbContent.append(line + "\n");  
  138.                     }  
  139.                 }  
  140.                 // 追加其它的属性  
  141.                 else  
  142.                 {  
  143.                     sbContent.append(line + "\n");  
  144.                 }  
  145.             }  
  146.             else  
  147.             {  
  148.                 // 追加读取的注释内容  
  149.                 sbContent.append(line + "\n");  
  150.             }  
  151.         }  
  152.            
  153.         encryptContent = sbContent.toString();  
  154.     }  
  155. }  

最后需要修改下applicationContext.xml文件,如下:

[java] view plain copy
  1. <bean id="propertyConfigurer1" class="com.huawei.smc.commons.DecryptPropertyPlaceholderConfigurer">  
  2. <property name="locations">  
  3.     <value>WEB-INF/classes/db.properties</value>  
  4. </property>  
  5.     </bean>  
  6.    
  7.     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
  8. <property name="driverClass" value="${db.driver}" />  
  9. <property name="jdbcUrl" value="${db.url}" />  
  10. <property name="user" value="${db.username}" />  
  11. <property name="password" value="${db.password}" />  
  12. <property name="checkoutTimeout" value="3000" />  
  13.    </bean>  

这样对属性的加密就完成了,Spring进行加载的完成后,属性就加密了

提示:如果在配置中有多个配置文件需要加载,并且这些属性文件不需要做任何处理,那就需要添加下面的配置:

[java] view plain copy
  1. <bean id="propertyConfigurer"  
  2. class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  3. <property name="order" value="1" />    
  4.         <property name="ignoreUnresolvablePlaceholders" value="true" />  
  5. <property name="locations">  
  6. <value>WEB-INF/classes/smc.properties</value>  
  7. </property>  

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果想更新系统怎么办 用钱宝恶意骚扰怎么办 乐贷款登录不了怎么办 急需6000元怎么办黑户 信而富绑卡失败怎么办 回访电话说错了怎么办 乐贷款逾期一天怎么办 被贷款公司骚扰怎么办 趣店账户异常怎么办 指还王要还款下载不了怎么办 随心花账户异常怎么办 账号已被锁定怎么办 哈罗单车被警告怎么办 禁止安装拼多多怎么办 该用户行为异常怎么办 设备被禁止登录怎么办 你的设备被禁封怎么办 监控显示未配置怎么办 监控显示不在线怎么办 兔聊认证不通过怎么办 高考成绩被屏蔽怎么办 百合号码换了怎么办 微粒贷还款限额怎么办 秒白条扣款失败怎么办 信用卡逾期没还怎么办 催收发侮辱短信怎么办? 快贷还清后被拒怎么办 任信用还不起怎么办 信用飞额度抢光怎么办 装修工钱要不回怎么办 装修客户不给钱怎么办 公司赖账不给怎么办 欠钱不还还把我设置黑名单怎么办 别人欠钱留我电话怎么办 微贷审核不通过怎么办 客户赖账不还怎么办 货款拖欠想赖账怎么办 有欠条还赖账怎么办 个人欠货款逃跑怎么办 微信借钱被拉黑怎么办 朋友借钱忘记还怎么办