一:介绍 1 2 3 应客户IT要求,需要对tomcat配置的JNDI中的password进行 解密处理,就是原本JNDI应该配置的明文密码变成密文的密 码,然后还要保证能连接数据库。
二:原理 2.1 明文的context.xml JNDI 1 2 3 4 5 6 7 8 9 10 11 12 13 <Resource name="jdbc/chncitosql02-buplanner" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="sa" password="a123456a" factory="org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://sit:21433;DatabaseName=businessplanner" />
2.2 密文的context.xml JNDI 1 2 3 4 5 6 7 8 9 10 11 12 13 <Resource name="jdbc/chncitosql02-buplanner" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="sa" password="cYQzL68vCszgg9BZ3BC8C6tiTyrM188lMWa8RWy0y0k=" factory="com.tohours.elearning.util.SecurityDataSourceFactory" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver" url="jdbc:sqlserver://sit:21433;DatabaseName=businessplanner" />
2.3 如何实现? 1 2 3 仔细的同学不难发现,上面的JNDI有一个factory配置不一样, 其中明文的是用的tomcat的factory,密文是用的自定义的,其实 就是再原本tomcat的factory基础上做调整,进行password的解密操作。
三:定义自己的数据库连接池 3.1 原理 1 在基于tomcat-dbcp.jar连接池的基础上做改造,重写BasicDataSourceFactory的一个方法。
3.2 步骤 1 2 3 4 项目引入tomcat-dbcp.jar,此文件在tomcat/lib下可以找到,也可以在下面地址下载, 我默认拿的是tomcat9的jar包,不同版本有区别,包名不一致,tomcat7和7之前用的是 org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory,tomcat7以后用的是 org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory
tomcat9的tomcat-dbcp.jar包下载
3.3 定义自己的SecurityDataSourceFactory类 1 2 3 4 我这里的全路径是com.tohours.elearning.util.SecurityDataSourceFactory, 所以密文的tomcat JNDI配置的是这个路径,其中SecurityDataSourceFactory 中引入了DBAesUtils.java,这个就是用的aes加解密,这里可以提换成自己用 的加解密的方法。
SecurityDataSourceFactory.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package com.tohours.elearning.util; import javax.naming.RefAddr; import javax.naming.Reference; import org.apache.log4j.Logger; import org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory; public class SecurityDataSourceFactory extends BasicDataSourceFactory { private Logger log = Logger.getLogger(SecurityDataSourceFactory.class); @Override @SuppressWarnings("rawtypes") public Object getObjectInstance(Object obj, javax.naming.Name name, javax.naming.Context nameCtx, java.util.Hashtable environment) throws Exception { if ((obj == null) || !(obj instanceof Reference)) { return null; } Reference ref = (Reference) obj; RefAddr ra = null; int len = ref.size(); for (int i = 0; i < len; i++) { ra = ref.get(i); log.info("type" + (i+1) + ":" + ra.getType()); if ("password".equalsIgnoreCase(ra.getType())) { ref.remove(i); ref.add(i, new TransformRefAddr(ra) { private static final long serialVersionUID = 1L; @Override public Object transform(Object obj) { return DBAesUtils.decrypt(obj.toString()); } }); } } return super.getObjectInstance(obj, name, nameCtx, environment); }; private abstract class TransformRefAddr extends RefAddr { private static final long serialVersionUID = 1L; private RefAddr refAddr; public TransformRefAddr(RefAddr refAddr) { super(refAddr.getType()); this.refAddr = refAddr; } @Override public Object getContent() { return this.transform(refAddr.getContent()); } public abstract Object transform(Object obj); } }