spring*.xml配置文件明文加密的实现
昊狼 人气:0这篇文章主要介绍了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))); } }
加载全部内容