ALL is Well!

          敏捷是一條很長的路,摸索著前進著

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            30 隨筆 :: 23 文章 :: 71 評論 :: 0 Trackbacks
          繼上一篇 擴展Spring-實現對外部引用的屬性文件的 屬性值 進行加密、解密 ,這次要實現的是對整個外部屬性文件進行加密,Spring在加載這個外部屬性文件時進行解密。
          分析過程與在 擴展Spring-實現對外部引用的屬性文件的 屬性值 進行加密、解密 中介紹的基本一致,只不過這次的入口就在 PropertiesLoaderSupport.java 這個抽象類的loadProperties方法。代碼片段:(注意注釋部分)
              @Override
              
          /**
               * Load properties into the given instance.
               * 
          @param props the Properties instance to load into
               * 
          @throws java.io.IOException in case of I/O errors
               * 
          @see #setLocations
               
          */

              
          protected void loadProperties(Properties props) throws IOException {
                  
          if (this.locations != null{
                      
          for (int i = 0; i < this.locations.length; i++{
                          Resource location 
          = this.locations[i];
                          
          if (logger.isInfoEnabled()) {
                              logger.info(
          "Loading properties file from " + location);
                          }

                          InputStream is 
          = null;
                          
          try {
                              
          // 屬性文件的輸入流
                              
          // 因為這個屬性文件是我們事先加密過的
                              
          // 所以在這里我們只要將此輸入流解密 再將其作為輸入流返回
                              
          // 其他的工作就按照Spring的流程即可
                              is = location.getInputStream();
                              
          if (location.getFilename().endsWith(XML_FILE_EXTENSION)) {
                                  
          this.propertiesPersister.loadFromXml(props, is);
                              }
           else {
                                  
          if (this.fileEncoding != null{
                                      
          this.propertiesPersister.load(props, new InputStreamReader(is,
                                          
          this.fileEncoding));
                                  }
           else {
                                      
          this.propertiesPersister.load(props, is);
                                  }

                              }

                          }
           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();
                              }

                          }

                      }

                  }

              }

          開始我們的實現過程:
          1.生成密鑰:DesUtil.java 這其中包括生成密鑰,對文件進行加密、解密操作。
          此解密方法返回輸入流對象,以便在 spring的loadProperties方法中使用。
          最終密鑰文件生成為:mytest.key
          package com.sec;

          import java.io.ByteArrayInputStream;
          import java.io.ByteArrayOutputStream;
          import java.io.FileOutputStream;
          import java.io.InputStream;
          import java.io.ObjectInputStream;
          import java.io.ObjectOutputStream;
          import java.io.OutputStream;
          import java.security.Key;
          import java.security.SecureRandom;

          import javax.crypto.Cipher;
          import javax.crypto.CipherInputStream;
          import javax.crypto.CipherOutputStream;
          import javax.crypto.KeyGenerator;

          import org.apache.commons.io.IOUtils;

          public class DesUtil {
              
          /**
               * 生成密鑰
               * 
               * 
          @param keyPath 密鑰文件
               
          */

              
          public static void createDesKey(String keyPath) {
                  FileOutputStream fos 
          = null;
                  ObjectOutputStream oos 
          = null;
                  
          try {
                      SecureRandom sr 
          = new SecureRandom();
                      KeyGenerator kg 
          = KeyGenerator.getInstance("DES");
                      kg.init(sr);
                      fos 
          = new FileOutputStream(keyPath);
                      oos 
          = new ObjectOutputStream(fos);
                      
          // 生成密鑰
                      Key key = kg.generateKey();
                      oos.writeObject(key);
                  }
           catch (Exception e) {
                      e.printStackTrace();
                  }
           finally {
                      IOUtils.closeQuietly(fos);
                      IOUtils.closeQuietly(oos);
                  }

              }


              
          /**
               * 獲得密鑰
               * 
               * 
          @param keyPath
               * 
          @return
               
          */

              
          public static Key getKey(String keyPath) {
                  Key kp 
          = null;
                  InputStream is 
          = null;
                  ObjectInputStream ois 
          = null;
                  
          try {
                      is 
          = ClassLoader.getSystemClassLoader().getResourceAsStream(keyPath);
                      
          return getKey(is);
                  }
           catch (Exception e) {
                      e.printStackTrace();
                  }
           finally {
                      IOUtils.closeQuietly(is);
                      IOUtils.closeQuietly(ois);
                  }

                  
          return kp;
              }

              
              
          /**
               * 獲得密鑰
               * 
          @param is
               * 
          @return
               
          */

              
          public static Key getKey(InputStream is) {
                  Key key 
          = null;
                  ObjectInputStream ois 
          = null;
                  
          try {
                      ois 
          = new ObjectInputStream(is);
                      key 
          = (Key)ois.readObject();
                  }
           catch (Exception e) {
                      e.printStackTrace();
                  }
           finally {
                      IOUtils.closeQuietly(ois);
                  }

                  
          return key;
              }


              
          /**
               * 加密源文件并保存到目標文件
               * 
               * 
          @param srcFile
               *            源文件
               * 
          @param destFile
               *            目標文件
               * 
          @param key
               *            加密用的Key
               * 
          @throws Exception
               
          */

              
          public static void encrypt(String srcFile, String destFile, Key key) throws Exception {
                  InputStream is 
          = null;
                  OutputStream out 
          = null;
                  CipherInputStream cis 
          = null;
                  
          try {
                      Cipher cipher 
          = Cipher.getInstance("DES");
                      cipher.init(Cipher.ENCRYPT_MODE, key);
                      is 
          = ClassLoader.getSystemClassLoader().getResourceAsStream(srcFile);
                      out 
          = new FileOutputStream(destFile);
                      cis 
          = new CipherInputStream(is, cipher);
                      
          byte[] buffer = new byte[1024];
                      
          int r;
                      
          while ((r = cis.read(buffer)) > 0{
                          out.write(buffer, 
          0, r);
                      }

                  }
           finally {
                      IOUtils.closeQuietly(cis);
                      IOUtils.closeQuietly(is);
                      IOUtils.closeQuietly(out);
                  }


              }


              
          /**
               * 解密文件
               * 
               * 
          @param file
               * 
          @param key
               * 
          @return
               * 
          @throws Exception
               
          */

              
          public static InputStream decrypt(InputStream is, Key key) throws Exception {
                  OutputStream out 
          = null;
                  CipherOutputStream cos 
          = null;
                  ByteArrayOutputStream bout 
          = null;
                  
          try {
                      Cipher cipher 
          = Cipher.getInstance("DES");
                      cipher.init(Cipher.DECRYPT_MODE, key);

                      bout 
          = new ByteArrayOutputStream();
                      
          byte[] buf = new byte[1024];
                      
          int count = 0;
                      
          while ((count = is.read(buf)) != -1{
                          bout.write(buf, 
          0, count);
                          buf 
          = new byte[1024];
                      }

                      
          byte[] orgData = bout.toByteArray();
                      
          byte[] raw = cipher.doFinal(orgData);
                      
          return new ByteArrayInputStream(raw);
                  }
           finally {
                      IOUtils.closeQuietly(cos);
                      IOUtils.closeQuietly(out);
                      IOUtils.closeQuietly(bout);
                  }

              }

          }


          2.對jdbc.properties文件進行加密:加密的方法為DesUtil的encrypt方法。
          jdbc.properties內容如下:
          driver=oracle.jdbc.OracleDriver
          dburl
          =jdbc:oracle:thin:@127.0.0.1:1521:root
          username
          =blogjava
          password
          =javadesps

          加密后得到文件desJdbc.properties,其內容如下:
          (ä8i6n??O?IÏ,d¢M?Ö?Ç??äðëñÖn$BÞ?d|ê?¾. ÓF—pêLylGýÓ?$Iv'ÕJô

          3.為了進行測試,新建SpringTestBean.java類,該類中只包含driver、url、username、password屬性以及get、set方法。
          package com.spring;

          import org.apache.commons.lang.builder.ToStringBuilder;
          import org.apache.commons.lang.builder.ToStringStyle;

          public class SpringTestBean {
              
          private String driver   = null;
              
          private String url      = null;
              
          private String username = null;
              
          private String password = null;
              
          //  get set 方法略

              
          /**
               * 重寫toString方法 觀察測試結果用
               
          */

              @Override
              
          public String toString() {
                  
          return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("driver", driver)
                      .append(
          "url", url).append("username", username).append("password", password)
                      .toString();
              }

          }


          4.配置applicationContext.xml文件。內容如下:
          <?xml version="1.0" encoding="UTF-8"?>
          <beans
              
          xmlns="http://www.springframework.org/schema/beans"
              xmlns:xsi
          ="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:aop
          ="http://www.springframework.org/schema/aop"
              xmlns:tx
          ="http://www.springframework.org/schema/tx"
              xmlns:context
          ="http://www.springframework.org/schema/context"
              xsi:schemaLocation
          ="http://www.springframework.org/schema/beans 
                                  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                                  http://www.springframework.org/schema/aop 
                                  http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
                                  http://www.springframework.org/schema/tx 
                                  http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                                  http://www.springframework.org/schema/context
                     http://www.springframework.org/schema/context/spring-context-2.5.xsd"

                     default-lazy-init
          ="true">
              
              
          <bean id="propertyConfigurer"
                  class
          ="com.spring.DecryptPropertyPlaceholderConfigurer">
                  
          <property name="locations">
                      
          <list>      
                          
          <value>classpath:com/spring/desJdbc.properties</value><!-- 加密后文件 -->
                      
          </list>
                  
          </property>
                  
          <property name="fileEncoding" value="utf-8"/> 
                  
          <property name="keyLocation" value="classpath:com/spring/mytest.key" /><!-- 密鑰文件位置 -->
              
          </bean> 
             
             
          <!-- 測試用bean -->
              
          <bean id="testBean" class="com.spring.SpringTestBean" destroy-method="close">
                  
          <property name="driver" value="${driver}" />
                  
          <property name="url" value="${dburl}" />
                  
          <property name="username" value="${username}" /> 
                  
          <property name="password" value="${password}" />
              
          </bean>
          </beans>

          5.實現自己的PropertyPlaceholderConfigurer類----DecryptPropertyPlaceholderConfigurer.java,繼承自Spring的PropertyPlaceholderConfigurer類:
          package com.spring;

          import java.io.IOException;
          import java.io.InputStream;
          import java.io.InputStreamReader;
          import java.util.Properties;

          import org.apache.commons.io.IOUtils;
          import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
          import org.springframework.core.io.Resource;
          import org.springframework.util.DefaultPropertiesPersister;
          import org.springframework.util.PropertiesPersister;

          import com.sec.DesUtil;

          public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
              
          private Resource[]          locations;
              
          private Resource            keyLocation;
              
          private PropertiesPersister propertiesPersister    = new DefaultPropertiesPersister();
              
          private String              fileEncoding           = "utf-8";
              
          private boolean             ignoreResourceNotFound = false;

              @Override
              
          public void setLocations(Resource[] locations) {
                  
          this.locations = locations;
              }


              @Override
              
          public void setFileEncoding(String encoding) {
                  
          this.fileEncoding = encoding;
              }


              @Override
              
          public void setIgnoreResourceNotFound(boolean ignoreResourceNotFound) {
                  
          this.ignoreResourceNotFound = ignoreResourceNotFound;
              }


              
          public void setKeyLocation(Resource keyLocation) {
                  
          this.keyLocation = keyLocation;
              }


              @Override
              
          /**
               * Load properties into the given instance.
               * 
          @param props the Properties instance to load into
               * 
          @throws java.io.IOException in case of I/O errors
               * 
          @see #setLocations
               
          */

              
          protected 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;        // 屬性文件輸入流
                          InputStream keyStream = null// 密鑰輸入流
                          InputStream readIs = null;    // 解密后屬性文件輸入流
                          try {
                              
          // 屬性文件輸入流
                              is = location.getInputStream();
                              
          // 密鑰輸入流
                              keyStream = keyLocation.getInputStream();
                              
          // 得到解密后的輸入流對象
                              readIs = DesUtil.decrypt(is, DesUtil.getKey(keyStream));
                              
          // 以下操作按照Spring的流程做即可
                              if (location.getFilename().endsWith(XML_FILE_EXTENSION)) {
                                  
          this.propertiesPersister.loadFromXml(props, readIs);
                              }
           else {
                                  
          if (this.fileEncoding != null{
                                      
          this.propertiesPersister.load(props, new InputStreamReader(readIs,
                                          
          this.fileEncoding));
                                  }
           else {
                                      
          this.propertiesPersister.load(props, readIs);
                                  }

                              }

                          }
           catch (Exception ex) {
                              
          if (this.ignoreResourceNotFound) {
                                  
          if (logger.isWarnEnabled()) {
                                      logger.warn(
          "Could not load properties from " + location + ""
                                          
          + ex.getMessage());
                                  }

                              }

                          }
           finally {
                              IOUtils.closeQuietly(is);
                              IOUtils.closeQuietly(keyStream);
                              IOUtils.closeQuietly(readIs);
                          }

                      }

                  }

              }

          }



          6.測試代碼:SpringCryptTest.java,這個代碼很簡單,就是用Spring去取得我們的測試bean----SpringTestBean,打印它的屬性,測試已經加密過的desJdbc.properties文件,能否被Spring正確解密并加載。
          package com.spring;

          import org.springframework.context.support.ClassPathXmlApplicationContext;

          public class SpringCryptTest {
              
          public static void main(String args[]) {
                  ClassPathXmlApplicationContext ctx 
          = new ClassPathXmlApplicationContext(
                      
          "com/spring/applicationContext.xml");
                  SpringTestBean bean 
          = (SpringTestBean)ctx.getBean("testBean");
                  System.out.println(bean.toString());
              }

          }

          執行結果:
          SpringTestBean[driver=oracle.jdbc.OracleDriver,url=jdbc:oracle:thin:@127.0.0.1:1521:root,username=blogjava,password=javadesps]

          OK。到此,Spring已經正確解密并加載了此外部屬性文件。

          本文為原創,歡迎轉載,轉載請注明出處BlogJava
          posted on 2010-10-02 12:44 李 明 閱讀(4378) 評論(8)  編輯  收藏 所屬分類: Spring

          評論

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-06-13 17:05 gsf
          我測試不成功啊
            回復  更多評論
            

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-06-13 17:05 gsf
          我的QQ:407584979  回復  更多評論
            

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-09-13 11:28 admin_yin
          @gsf
          我測試也沒有成功,請問你的可以了嗎?QQ:26509925  回復  更多評論
            

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-09-18 21:32 李 明
          把不成功的信息發一下,比如出現什么樣的情況,描述一下,有異常,貼一下。@gsf
            回復  更多評論
            

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-09-18 21:32 李 明
          把不成功的信息發一下,比如出現什么樣的情況,描述一下,有異常,貼一下。@admin_yin
            回復  更多評論
            

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-09-19 18:07 admin_yin
          @李 明
          我測試時成功了,但是要是連接數據庫話,不知在application中怎么配置了,目前配置如:
          <bean id="propertyConfigurer"
          class="config.ReadEncryptedPropertyPlaceholderConfigurer">
          <property name="locations">
          <list>
          <value>classpath:config/db.properties</value><!-- 加密后文件 -->
          </list>
          </property>
          <property name="fileEncoding" value="utf-8"/>
          <property name="keyLocation" value="classpath:config/key.dat" /><!-- 密鑰文件位置 -->
          </bean>

          <!-- 測試用bean -->
          <bean id="testBean" class="config.SpringTestBean" >
          <property name="driver" value="${driver}"/>
          <property name="url" value="${dburl}" />
          <property name="username" value="${username}" />
          <property name="password" value="${password}" />
          </bean>


          <bean id="datasource"
          class="org.apache.commons.dbcp.BasicDataSource">
          <property name="driverClassName"
          value="com.microsoft.sqlserver.jdbc.SQLServerDriver">
          </property>
          <!-- <property name="url"-->
          <!-- value="jdbc:sqlserver://localhost:1433;DatabaseName=stu">-->
          <!-- </property>-->
          <!-- <property name="username" value="sa"></property>-->
          <!-- <property name="password" value="sa"></property>-->
          </bean>
          <bean id="sessionfactory"
          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
          <property name="dataSource">
          <ref bean="datasource" />
          </property>
          <property name="hibernateProperties">
          <props>
          <prop key="hibernate.dialect">
          org.hibernate.dialect.SQLServerDialect
          </prop>
          </props>
          </property>
          <property name="mappingResources">
          <list>
          <value>vo/Student.hbm.xml</value></list>
          </property>
          </bean>
          <bean id="StudentDAO" class="vo.StudentDAO">
          <property name="sessionFactory">
          <ref bean="sessionfactory" />
          </property>
          </bean>  回復  更多評論
            

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-09-20 11:52 admin_yin
          @李 明
          我在Spring里面配置,當啟動Tomcat的時候能解密,但是出現了如以下的錯誤:
          信息: Initializing Spring root WebApplicationContext
          dburl=jdbc:sqlserver://localhost:1433;databaseName=stu

          password=sa

          driver=com.microsoft.sqlserver.jdbc.SQLServerDriver

          username=sa

          2011-9-20 11:49:33 org.apache.catalina.core.StandardContext listenerStart
          嚴重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
          org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'datasource' defined in class path resource [applicationContext.xml]: Could not resolve placeholder 'driver'
          at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.processProperties(PropertyPlaceholderConfigurer.java:268)
          at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:75)
          at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:553)
          at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:527)
          at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:362)
          at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255)
          at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
          at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
          at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3843)
          at org.apache.catalina.core.StandardContext.start(StandardContext.java:4342)
          at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
          at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
          at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
          at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:926)
          at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:889)
          at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
          at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1149)
          at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
          at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
          at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
          at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
          at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
          at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
          at org.apache.catalina.core.StandardService.start(StandardService.java:516)
          at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
          at org.apache.catalina.startup.Catalina.start(Catalina.java:578)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
          at java.lang.reflect.Method.invoke(Method.java:597)
          at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
          at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
          2011-9-20 11:49:33 org.apache.catalina.core.StandardContext start

          ----------------------------------------------------
          難道配置不對嗎?配置
          <bean id="propertyConfigurer"
          class="test0x31.ReadEncryptedPropertyPlaceholderConfigurer">
          <property name="locations">
          <list>
          <value>classpath:db.properties</value><!-- 加密后文件 -->
          </list>
          </property>
          <property name="fileEncoding" value="utf-8"/>
          <!-- <property name="keyLocation" value="classpath:config/key.dat" /> 密鑰文件位置 -->
          </bean>
          <bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource">
          <property name="driverClassName" value="${driver}"/>
          <property name="url" value="${dburl}" />
          <property name="username" value="${username}" />
          <property name="password" value="${password}" />
          </bean>
          <bean id="sessionfactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
          <property name="dataSource">
          <ref bean="datasource" />
          </property>
          <property name="hibernateProperties">
          <props>
          <prop key="hibernate.dialect">
          org.hibernate.dialect.SQLServerDialect
          </prop>
          </props>
          </property>
          <property name="mappingResources">
          <list>
          <value>vo/Student.hbm.xml</value></list>
          </property>
          </bean>
          <bean id="StudentDAO" class="vo.StudentDAO">
          <property name="sessionFactory">
          <ref bean="sessionfactory" />
          </property>
          </bean>  回復  更多評論
            

          # re: 擴展Spring-實現對外部引用的屬性文件進行加密、解密 2011-09-25 09:43 李 明
          根據你的異常信息是說 沒有 placeholder 關鍵字 driver,你檢查一下config/db.properties 的配置,是否配置了 driver,或者關鍵字有沒有寫錯。@admin_yin
            回復  更多評論
            

          主站蜘蛛池模板: 鹤壁市| 江山市| 宜兰市| 高州市| 林口县| 临朐县| 瓮安县| 册亨县| 若尔盖县| 商南县| 新乐市| 广南县| 樟树市| 漳州市| 昌江| 舒城县| 木里| 福州市| 谢通门县| 松桃| 建宁县| 莎车县| 栖霞市| 富民县| 琼中| 嘉祥县| 陕西省| 哈巴河县| 兴化市| 甘洛县| 边坝县| 开鲁县| 四平市| 北流市| 韶山市| 甘洛县| 平和县| 牙克石市| 玉树县| 宜良县| 寿宁县|