当需要对JNDI数据源的数据进行加密的时候,可以通过自定义Factory类实现,Factory负责为其服务创建适当的InitialContext对象。不定义factory类时默认访问tomcat下org\apache\tomcat\dbcp\dbcp\BasicDataSourceFactory该类,为了不碰tomcat原标准,将该类源码复制一份并加入解码方法即可。以tomcat为例,将数据源的密码进行加密(其中密码已进行DES加密),在tomcat目录下conf\context.xml中的Resource节点添加factory属性并赋值自定义类路径:
自定义类基于源码基础上加入解密方法,并在createDataSource方法中针对密码进行解密:dataSource.setPassword(decrypt(value))(其中BasicDataSource这个类引用的是tomcat路径下org.apache.tomcat.dbcp.dbcp.BasicDataSource而不是org.apache.commons.dbcp.dbcp.BasicDataSource下的,具体根据实际情况引入)
package org.apache.commons.dbcp;
import java.io.ByteArrayInputStream;
import java.security.SecureRandom;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
import javax.sql.DataSource;
import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
public class DecryptBasicDataSourceFactory implements ObjectFactory {
private static final String[] ALL_PROPERTIES = new String[]{PROP_DEFAULTAUTOCOMMIT, PROP_DEFAULTREADONLY, PROP_DEFAULTTRANSACTIONISOLATION, PROP_DEFAULTCATALOG, PROP_DRIVERCLASSNAME, PROP_MAXACTIVE, PROP_MAXIDLE, PROP_MINIDLE, PROP_INITIALSIZE, PROP_MAXWAIT, PROP_TESTONBORROW, PROP_TESTONRETURN, PROP_TIMEBETWEENEVICTIONRUNSMILLIS, PROP_NUMTESTSPEREVICTIONRUN, PROP_MINEVICTABLEIDLETIMEMILLIS, PROP_TESTWHILEIDLE, PROP_PASSWORD, PROP_URL, PROP_USERNAME, PROP_VALIDATIONQUERY, PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED, PROP_REMOVEABANDONED, PROP_REMOVEABANDONEDTIMEOUT, PROP_LOGABANDONED, PROP_POOLPREPAREDSTATEMENTS, PROP_MAXOPENPREPAREDSTATEMENTS, PROP_CONNECTIONPROPERTIES};
private static final String DES = "DES";
private static final String PASSWORD_CRYPT_KEY = "fuli_tomcat";
private static final String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
private static final String PROP_CONNECTIONPROPERTIES = "connectionProperties";
private static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
private static final String PROP_DEFAULTCATALOG = "defaultCatalog";
private static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
private static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
private static final String PROP_DRIVERCLASSNAME = "driverClassName";
private static final String PROP_INITIALSIZE = "initialSize";
private static final String PROP_LOGABANDONED = "logAbandoned";
private static final String PROP_MAXACTIVE = "maxActive";
private static final String PROP_MAXIDLE = "maxIdle";
private static final String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
private static final String PROP_MAXWAIT = "maxWait";
private static final String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
private static final String PROP_MINIDLE = "minIdle";
private static final String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
private static final String PROP_PASSWORD = "password";
private static final String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
private static final String PROP_REMOVEABANDONED = "removeAbandoned";
private static final String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
private static final String PROP_TESTONBORROW = "testOnBorrow";
private static final String PROP_TESTONRETURN = "testOnReturn";
private static final String PROP_TESTWHILEIDLE = "testWhileIdle";
private static final String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
private static final String PROP_URL = "url";
private static final String PROP_USERNAME = "username";
private static final String PROP_VALIDATIONQUERY = "validationQuery";
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
if (obj == null || !(obj instanceof Reference)) {
return null;
}
Reference ref = (Reference) obj;
if (!"javax.sql.DataSource".equals(ref.getClassName())) {
return null;
}
Properties properties = new Properties();
for (String propertyName : ALL_PROPERTIES) {
RefAddr ra = ref.get(propertyName);
if (ra != null) {
properties.setProperty(propertyName, ra.getContent().toString());
}
}
return createDataSource(properties);
}
public static DataSource createDataSource(Properties properties) throws Exception {
BasicDataSource dataSource = new BasicDataSource();
String value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
if (value != null) {
dataSource.setDefaultAutoCommit(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_DEFAULTREADONLY);
if (value != null) {
dataSource.setDefaultReadOnly(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION);
if (value != null) {
int level;
if ("NONE".equalsIgnoreCase(value)) {
level = 0;
} else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
level = 2;
} else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
level = 1;
} else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
level = 4;
} else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
level = 8;
} else {
try {
level = Integer.parseInt(value);
} catch (NumberFormatException e) {
System.err.println("Could not parse defaultTransactionIsolation: " + value);
System.err.println("WARNING: defaultTransactionIsolation not set");
System.err.println("using default value of database driver");
level = -1;
}
}
dataSource.setDefaultTransactionIsolation(level);
}
value = properties.getProperty(PROP_DEFAULTCATALOG);
if (value != null) {
dataSource.setDefaultCatalog(value);
}
value = properties.getProperty(PROP_DRIVERCLASSNAME);
if (value != null) {
dataSource.setDriverClassName(value);
}
value = properties.getProperty(PROP_MAXACTIVE);
if (value != null) {
dataSource.setMaxActive(Integer.parseInt(value));
}
value = properties.getProperty(PROP_MAXIDLE);
if (value != null) {
dataSource.setMaxIdle(Integer.parseInt(value));
}
value = properties.getProperty(PROP_MINIDLE);
if (value != null) {
dataSource.setMinIdle(Integer.parseInt(value));
}
value = properties.getProperty(PROP_INITIALSIZE);
if (value != null) {
dataSource.setInitialSize(Integer.parseInt(value));
}
value = properties.getProperty(PROP_MAXWAIT);
if (value != null) {
dataSource.setMaxWait(Long.parseLong(value));
}
value = properties.getProperty(PROP_TESTONBORROW);
if (value != null) {
dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_TESTONRETURN);
if (value != null) {
dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
if (value != null) {
dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
}
value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
if (value != null) {
dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
}
value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
if (value != null) {
dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
}
value = properties.getProperty(PROP_TESTWHILEIDLE);
if (value != null) {
dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_PASSWORD);
if (value != null) {
//解密
dataSource.setPassword(decrypt(value));
}
value = properties.getProperty(PROP_URL);
if (value != null) {
dataSource.setUrl(value);
}
value = properties.getProperty(PROP_USERNAME);
if (value != null) {
dataSource.setUsername(value);
}
value = properties.getProperty(PROP_VALIDATIONQUERY);
if (value != null) {
dataSource.setValidationQuery(value);
}
value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
if (value != null) {
dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_REMOVEABANDONED);
if (value != null) {
dataSource.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
if (value != null) {
dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
}
value = properties.getProperty(PROP_LOGABANDONED);
if (value != null) {
dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS);
if (value != null) {
dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
}
value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS);
if (value != null) {
dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
}
value = properties.getProperty(PROP_CONNECTIONPROPERTIES);
if (value != null) {
Properties p = getProperties(value);
Enumeration e2 = p.propertyNames();
while (e2.hasMoreElements()) {
String propertyName = (String) e2.nextElement();
dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
}
}
return dataSource;
}
private static Properties getProperties(String propText) throws Exception {
Properties p = new Properties();
if (propText != null) {
p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
}
return p;
}
private static String decrypt(String data) {
try {
return new String(decrypt(hex2byte(data.getBytes()), PASSWORD_CRYPT_KEY.getBytes()));
} catch (Exception e) {
return null;
}
}
private static byte[] hex2byte(byte[] b) {
if (b.length % 2 != 0) {
throw new IllegalArgumentException("长度不是偶数");
}
byte[] b2 = new byte[(b.length / 2)];
for (int n = 0; n < b.length; n += 2) {
b2[n / 2] = (byte) Integer.parseInt(new String(b, n, 2), 16);
}
return b2;
}
private static byte[] decrypt(byte[] src, byte[] key) throws Exception {
SecureRandom sr = new SecureRandom();
SecretKey securekey = SecretKeyFactory.getInstance(DES).generateSecret(new DESKeySpec(key));
Cipher cipher = Cipher.getInstance(DES);
cipher.init(2, securekey, sr);
return cipher.doFinal(src);
}
}
Finally将其打包放在tomcat lib下面即可!!!