spring*.xml配置文件明文加密的实现
作者:昊狼
这篇文章主要介绍了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配置文件加密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!