spring*.xml配置文件明文加密的實現
說明:客戶要求spring*.xml中Oracle/Redis/MongoDB的IP、端口、用戶名、密碼不能明文存放,接到需求的我,很無奈,但是還是的硬著頭皮搞
系統架構:spring+mvc(Oracle是用jdbc自己封裝的接口)
1.數據庫配置文件加密
原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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byType"> <context:component-scan base-package="cn.geoff" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <!-- Database Connection Pool --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="jdbc:oracle:thin:@192.168.100.100:1521:orcl"/> <property name="username" value="Geoff"/> <property name="password" value="123456"/> <property name="validationQuery" value="select 'x' from dual"/> ..... </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans>
加密實現過程
思路:繼承DruidDataSource,在初始化set值的時候進行解密
/** * 數據庫連接解密 * @author: Geoff * @create: 2020-12-30 16:46 **/ public class DataBaseXml extends DruidDataSource { /** * Log4j logger */ private final static Logger lg = LoggerFactory.getLogger(DataBaseXml.class); @Override public String getUrl() { return this.jdbcUrl; } @Override public void setUrl(String jdbcUrl) { if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("數據庫【jdbcUrl】解密初始化加載..."); try { jdbcUrl = Encryption.decrypt(jdbcUrl, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("數據庫【jdbcUrl】密文解密失敗..."); e.printStackTrace(); } } this.jdbcUrl = jdbcUrl; } @Override public String getUsername() { return this.username; } @Override public void setUsername(String username) { if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("數據庫【username】解密初始化加載..."); try { username = Encryption.decrypt(username, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("數據庫【username】密文解密失敗..."); e.printStackTrace(); } } this.username = username; } @Override public String getPassword() { return this.password; } @Override public void setPassword(String password) { if(GEOFF.DATA_BASE_IS_ENCRYPTION){ lg.info("數據庫【password】解密初始化加載..."); try { password = Encryption.decrypt(password, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("數據庫【password】密文解密失敗..."); e.printStackTrace(); } } this.password = password; } }
修改後配置文件
<?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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byType"> <context:component-scan base-package="cn.GEOFF" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> </context:component-scan> <bean id="dataSource" class="cn.GEOFF.framework.core.DataBaseXml" init-method="init" destroy-method="close"> <property name="url" value="4lZ4l804zIDqOJ5Wt3VNVLZvSLSDqCuQwhg5cAbQ1VG/vx+x+pEJQ6VJmLPO+PKK"/> <property name="username" value="PFEz8V4uvb06KhQxCLvLNA=="/> <property name="password" value="mMckYd6C5fo="/> <property name="validationQuery" value="select 'x' from dual"/> ..... </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans>
2.Redis配置文件加密
原配置文件
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <!-- Jedis --> <beans default-autowire="byName"> <!-- Default Pool Config --> <bean id="defaultJedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="5"/> <property name="maxIdle" value="2"/> <property name="minIdle" value="2"/> <property name="testOnBorrow" value="true"/> <property name="testOnReturn" value="true"/> <property name="testWhileIdle" value="true"/> </bean> <bean id="one" class="redis.clients.jedis.JedisPool" destroy-method="destroy"> <constructor-arg index="0" ref="defaultJedisPoolConfig"/> <constructor-arg index="1" value="127.0.0.1" type="java.lang.String"/> <constructor-arg index="2" value="6379" type="int"/> <constructor-arg index="3" value="0" type="int"/> <constructor-arg index="4" value="123456" type="java.lang.String"/> </bean> <bean id="two" class="redis.clients.jedis.JedisPool" destroy-method="destroy"> <constructor-arg index="0" ref="defaultJedisPoolConfig"/> <constructor-arg index="1" value="127.0.0.1" type="java.lang.String"/> <constructor-arg index="2" value="6379" type="int"/> <constructor-arg index="3" value="0" type="int"/> <constructor-arg index="4" value="123456" type="java.lang.String"/> </bean> <bean id="three" class="redis.clients.jedis.JedisPool" destroy-method="destroy"> <constructor-arg index="0" ref="defaultJedisPoolConfig"/> <constructor-arg index="1" value="127.0.0.1" type="java.lang.String"/> <constructor-arg index="2" value="6379" type="int"/> <constructor-arg index="3" value="0" type="int"/> <constructor-arg index="4" value="123456" type="java.lang.String"/> </bean> </beans>
加密實現思路:由於JedisPool使用構造函數來創建,所以繼承JedisPool後,在調用JedisPool構造函數的時候,調用static解密方法進行解密
import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.*; /** * redis數據庫用戶名密碼解密 * @author: Geoff * @create: 2020-12-30 17:20 **/ public class JedisPoolXml extends JedisPool{ /** * Log4j logger */ private final static Logger lg = LoggerFactory.getLogger(JedisPoolXml.class); public JedisPoolXml(GenericObjectPoolConfig poolConfig, String host, String port, String timeout, String password) { super(poolConfig,decryptHost(host),decryptPort(port),decryptTimeout(timeout),decryptPassword(password), 0, (String)null); } private JedisPoolXml(GenericObjectPoolConfig poolConfig, String host, String port,String timeout, String password, String database){ super(poolConfig,decryptHost(host),decryptPort(port),decryptTimeout(timeout),decryptPassword(password),decryptDatabase(database)); } private static String decryptHost(String host){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("Redis【host】解密初始化加載..."); try { host = Encryption.decrypt(host, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("Redis【host】密文解密失敗..."); e.printStackTrace(); } } return host; } private static int decryptPort(String port){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("Redis【port】解密初始化加載..."); try { port = Encryption.decrypt(port, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("Redis【port】密文解密失敗..."); e.printStackTrace(); } } return Integer.parseInt(port); } private static int decryptTimeout(String timeout){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("Redis【timeout】解密初始化加載..."); try { timeout = Encryption.decrypt(timeout, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("Redis【timeout】密文解密失敗..."); e.printStackTrace(); } } return Integer.parseInt(timeout); } private static String decryptPassword(String password){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("Redis【password】解密初始化加載..."); try { password = Encryption.decrypt(password, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("Redis【password】密文解密失敗..."); e.printStackTrace(); } } return password; } private static int decryptDatabase(String database){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("Redis【database】解密初始化加載..."); try { database = Encryption.decrypt(database, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("Redis【database】密文解密失敗..."); e.printStackTrace(); } } return Integer.parseInt(database); } }
修改後xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <!-- Jedis --> <beans default-autowire="byName"> <bean id="defaultJedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="5"/> <property name="maxIdle" value="2"/> <property name="minIdle" value="2"/> <property name="testOnBorrow" value="true"/> <property name="testOnReturn" value="true"/> <property name="testWhileIdle" value="true"/> </bean> <bean id="one" class="cn.GEOFF.framework.core.JedisPoolXml" destroy-method="destroy"> <constructor-arg index="0" ref="defaultJedisPoolConfig"/> <constructor-arg index="1" value="N98/M6A3acRnYMqIQEXGEg==" type="java.lang.String"/> <constructor-arg index="2" value="INDccYoGS/Y=" type="java.lang.String"/> <constructor-arg index="3" value="CXszBZysXWY=" type="java.lang.String"/> <constructor-arg index="4" value="mMckYd6C5fo=" type="java.lang.String"/> </bean> <bean id="two" class="cn.GEOFF.framework.core.JedisPoolXml" destroy-method="destroy"> <constructor-arg index="0" ref="defaultJedisPoolConfig"/> <constructor-arg index="1" value="N98/M6A3acRnYMqIQEXGEg==" type="java.lang.String"/> <constructor-arg index="2" value="INDccYoGS/Y=" type="java.lang.String"/> <constructor-arg index="3" value="CXszBZysXWY=" type="java.lang.String"/> <constructor-arg index="4" value="mMckYd6C5fo=" type="java.lang.String"/> </bean> <bean id="three" class="cn.GEOFF.framework.core.JedisPoolXml" destroy-method="destroy"> <constructor-arg index="0" ref="defaultJedisPoolConfig"/> <constructor-arg index="1" value="N98/M6A3acRnYMqIQEXGEg==" type="java.lang.String"/> <constructor-arg index="2" value="INDccYoGS/Y=" type="java.lang.String"/> <constructor-arg index="3" value="CXszBZysXWY=" type="java.lang.String"/> <constructor-arg index="4" value="mMckYd6C5fo=" type="java.lang.String"/> </bean> </beans>
3.MongoDB配置文件加密(使用的是spring-data-mognodb框架)
原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:mongo="http://www.springframework.org/schema/data/mongo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd"> <mongo:mongo-client id="mongoClient" host="192.168.100.100" port="27017" credentials="jyzq_zsc:123456@JYZQ_ZSC"> </mongo:mongo-client> <!-- Factory --> <mongo:db-factory id="mongoDbFactory" dbname="PFEz8V4uvb06KhQxCLvLNA==" mongo-ref="mongoClient"/> <mongo:db-factory id="mongoDbFactory" dbname="JYZQ_ZSC" mongo-ref="mongoClient"/> <mongo:mapping-converter id="converter" db-factory-ref="mongoDbFactory"/> <!-- Grid FS Template --> <bean id="gridFsTemplate" class="org.springframework.data.mongodb.gridfs.GridFsTemplate"> <constructor-arg ref="mongoDbFactory"/> <constructor-arg ref="converter"/> </bean> <!-- Mongo Template --> <bean id="documentTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg ref="mongoDbFactory"/> <constructor-arg ref="converter"/> </bean> </beans>
加密思路:由於項目使用的時候是獲取bean的方式來獲取MongoTemplate和mongoDbFactory的,嘗試過各種方法來繼承後加密,但是最後都不行,後面隻能通過手動的方法進行初始化,並將對應MongoTemplate和mongoDbFactory註入到bean中
import com.mongodb.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.gridfs.GridFsTemplate; import java.util.ArrayList; import java.util.List; /** * @author: Geoff * @create: 2020-12-31 16:15 **/ @Configuration public class MongoDBXml { /** * Log4j logger */ private final static Logger lg = LoggerFactory.getLogger(MongoDBXml.class); private String host; private Integer port; private String userName; private String passWord; private String dataBase; private SimpleMongoDbFactory mongoDbFactory = null; private MappingMongoConverter converter = null; public String getHost() { return host; } public void setHost(String host) { this.host = decryptHost(host); } public Integer getPort() { return port; } public void setPort(String port) { this.port = decryptPort(port); } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = decryptUserName(userName); } public String getPassWord() { return passWord; } public void setPassWord(String passWord) { this.passWord = decryptPassword(passWord); } public String getDataBase() { return dataBase; } public void setDataBase(String dataBase) { this.dataBase = decryptDatabase(dataBase); } private String decryptHost(String host){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("MongoDB【host】解密初始化加載..."); try { host = Encryption.decrypt(host, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("MongoDB【host】密文解密失敗..."); e.printStackTrace(); } } return host; } private int decryptPort(String port){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("MongoDB【port】解密初始化加載..."); try { port = Encryption.decrypt(port, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("MongoDB【port】密文解密失敗..."); e.printStackTrace(); } } return Integer.parseInt(port); } private String decryptUserName(String userName){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("MongoDB【userName】解密初始化加載..."); try { userName = Encryption.decrypt(userName, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("MongoDB【userName】密文解密失敗..."); e.printStackTrace(); } } return userName; } private String decryptPassword(String passWord){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("MongoDB【password】解密初始化加載..."); try { passWord = Encryption.decrypt(passWord, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("MongoDB【password】密文解密失敗..."); e.printStackTrace(); } } return passWord; } private String decryptDatabase(String dataBase){ if(GEOFF.DATA_BASE_IS_ENCRYPTION) { lg.info("MongoDB【database】解密初始化加載..."); try { dataBase = Encryption.decrypt(dataBase, GEOFF.DATA_BASE_ENCRYPTION_KEY); } catch (Exception e) { lg.error("MongoDB【database】密文解密失敗..."); e.printStackTrace(); } } return dataBase; } public void init() { MongoClientOptions.Builder build = new MongoClientOptions.Builder(); MongoClientOptions options = build.build(); try { List<ServerAddress> addrs = new ArrayList<ServerAddress>(); ServerAddress serverAddress = new ServerAddress(host, port); addrs.add(serverAddress); MongoCredential credential = MongoCredential.createScramSha1Credential(userName, dataBase, passWord.toCharArray()); List<MongoCredential> credentials = new ArrayList<MongoCredential>(); credentials.add(credential); MongoClient mongoClient = new MongoClient(addrs, credentials, options); mongoDbFactory = new SimpleMongoDbFactory(mongoClient, dataBase); DefaultDbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory); MongoMappingContext mongoMappingContext = new MongoMappingContext(); converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext); lg.info(" mongodb客戶端創建成功 "); } catch (Exception e) { lg.info(" mongodb客戶端創建失敗 "); e.printStackTrace(); } documentTemplate(); gridFsTemplate(); } @Bean public MongoTemplate documentTemplate() { if (mongoDbFactory != null && converter != null) { lg.info("MongoTemplate初始化成功......"); MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, converter); return mongoTemplate; } else { lg.error("MongoTemplate初始化失敗......"); return null; } } @Bean public GridFsTemplate gridFsTemplate() { if (mongoDbFactory != null && converter != null) { lg.info("GridFsTemplate初始化成功......"); GridFsTemplate gridFsTemplate = new GridFsTemplate(mongoDbFactory, converter); return gridFsTemplate; } else { lg.error("GridFsTemplate初始化失敗......"); return null; } } public void destroy(){ try { this.mongoDbFactory.destroy(); } catch (Exception e) { e.printStackTrace(); } } }
修改後配置文件
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <!-- mongoDB --> <beans> <bean id="mongoDBXml" class="cn.GEOFF.framework.core.MongoDBXml" init-method="init" destroy-method="destroy" > <property name="host" value="PpmNMR+X2UIVhG8gmNFFqg=="/> <property name="port" value="51QH8fifl1k="/> <property name="userName" value="yre5DufK9os6KhQxCLvLNA=="/> <property name="passWord" value="mMckYd6C5fo="/> <property name="dataBase" value="PFEz8V4uvb06KhQxCLvLNA=="/> </bean> </beans>
4.最後附上對應的加解密類
import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import java.security.Key; import java.security.SecureRandom; /** * 加密生成token的方法 * * @author: Geoff * @create: 2020-12-30 17:03 **/ public class Encryption { // 算法名稱 public static final String KEY_ALGORITHM = "DES"; // 算法名稱/加密模式/填充方式 // DES共有四種工作模式-->>ECB:電子密碼本模式、CBC:加密分組鏈接模式、CFB:加密反饋模式、OFB:輸出反饋模式 public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding"; /** * 生成密鑰key對象 * * @param * @return 密鑰對象 * @throws Exception */ private static SecretKey keyGenerator(String keyStr) throws Exception { byte[] input = HexString2Bytes(keyStr); DESKeySpec desKey = new DESKeySpec(input); // 創建一個密匙工廠,然後用它把DESKeySpec轉換成 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM); SecretKey securekey = keyFactory.generateSecret(desKey); return securekey; } /** * 從十六進制字符串到字節數組轉換 */ public static byte[] HexString2Bytes(String hexStr) { byte[] keyBytes = hexStr.getBytes(); if (keyBytes.length == 16) { byte[] tmpKey = new byte[24]; System.arraycopy(keyBytes, 0, tmpKey, 0, 16); System.arraycopy(keyBytes, 0, tmpKey, 16, 8); keyBytes = tmpKey; } return keyBytes; } /** * 加密數據 * * @param data 待加密數據 * @param key 密鑰 * @return 加密後的數據 */ public static String encrypt(String data, String key) throws Exception { Key deskey = keyGenerator(key); // 實例化Cipher對象,它用於完成實際的加密操作 Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); SecureRandom random = new SecureRandom(); // 初始化Cipher對象,設置為加密模式 cipher.init(Cipher.ENCRYPT_MODE, deskey, random); byte[] results = cipher.doFinal(data.getBytes()); // 執行加密操作。加密後的結果通常都會用Base64編碼進行傳輸 return Base64.encodeBase64String(results); } /** * 解密數據 * * @param data 待解密數據 * @param key 密鑰 * @return 解密後的數據 */ public static String decrypt(String data, String key) throws Exception { Key deskey = keyGenerator(key); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); // 初始化Cipher對象,設置為解密模式 cipher.init(Cipher.DECRYPT_MODE, deskey); // 執行解密操作 return new String(cipher.doFinal(Base64.decodeBase64(data))); } }
到此這篇關於spring*.xml配置文件明文加密的實現的文章就介紹到這瞭,更多相關spring*.xml配置文件加密內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳解SpringBean基於XML的裝配
- Spring IOC創建對象的兩種方式
- Spring詳細講解@Autowired註解
- 詳解spring如何使用註解開發
- Spring項目中使用Junit單元測試並配置數據源的操作