在實際開發中,遇到過這麼一個需求,tomcat連接的oracle數據庫,數據庫的密碼爲明文顯示,客戶提出不能爲明文顯示,必須是密文的方式。那麼我如何做呢?下面說一下
一、tomcat連接oracle方式
在tomcat的context.xml中配置(筆者tomcat版本爲tomcat-7.0.69)如下
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Resource name="jdbc/srw"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
maxActive="1000"
minIdle="100"
maxIdle="800"
maxWait="10000"
username="system"
password="123456"
url="jdbc:oracle:thin:@//xxx.xxx.xx.xx:1521/orcl"
testWhileIdle = "true"
testOnBorrow="true"
validationQueryTimeout="30"
validationQuery="select 1 from dual"
timeBetweenEvictionRunsMillis = "30000"
minEvictableIdleTimeMillis = "1800000"
numTestsPerEvictionRun="10"
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true"
/>
<Resource name="jdbc/sro"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
maxActive="500"
minIdle="50"
maxIdle="400"
maxWait="10000"
username="system"
password="123456"
url="jdbc:oracle:thin:@//xxx.xxxxx.xx:1521/orcl"
testWhileIdle = "true"
testOnBorrow="true"
validationQueryTimeout="30"
validationQuery="select 1 from dual"
timeBetweenEvictionRunsMillis = "30000"
minEvictableIdleTimeMillis = "1800000"
numTestsPerEvictionRun="10"
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true"
/>
二、修改思路(在此連接密碼部分加密,然後在項目裏獲取密碼部分然後進行解密在替換回去,加密方式由自己定)
三、編寫解密類需要繼承tomcat的BasicDataSourceFactory類,是tomcat的dbcp包中的
package com.simp.tomcat;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;
/**
*客戶要求 連接oracle時需要將 密碼進行加密連接,需要在代碼中進行解密
* @author mc
* 2019-10-28
*/
public class EncryptedDataSourceFactory extends BasicDataSourceFactory {
@SuppressWarnings("rawtypes")
public Object getObjectInstance(Object obj, Name name, Context nameCtx,Hashtable environment) throws Exception {
if (obj instanceof Reference) {
//用戶名不需要加密,所以去掉解密
//setUsername((Reference) obj);
setPassword((Reference) obj);
}
return super.getObjectInstance(obj, name, nameCtx, environment);
}
//用戶名不需要解密所以註釋掉
/*private void setUsername(Reference ref) throws Exception {
findDecryptAndReplace("username", ref);
}*/
private void setPassword(Reference ref) throws Exception {
findDecryptAndReplace("password", ref);
}
private void findDecryptAndReplace(String refType, Reference ref) throws Exception {
int idx = find(refType, ref);
String decrypted = decrypt(idx, ref);
replace(idx, refType, decrypted, ref);
}
/**
* 將解密後的字符串替換配置文件裏的加密後的字符串
* @param idx
* @param refType
* @param newValue
* @param ref
* @throws Exception
*/
private void replace(int idx, String refType, String newValue, Reference ref)
throws Exception {
ref.remove(idx);
ref.add(idx, new StringRefAddr(refType, newValue));
}
/**
* 解密
* @param idx 請求所在位置
* @param ref 請求資源
* @return
* @throws Exception
*/
private String decrypt(int idx, Reference ref) throws Exception {
//解密方法
//return G4Utils.decryptBasedDes(ref.get(idx).getContent().toString());
String pw = ref.get(idx).getContent().toString();
System.out.println("原密碼: "+pw);
String newPwd = this.decode(pw);
System.out.println("解密之後密碼: "+newPwd);
return newPwd;
}
/**
* 找到需要解密的字符串的位置
* @param addrType
* @param ref
* @return
* @throws Exception
*/
@SuppressWarnings("rawtypes")
private int find(String addrType, Reference ref) throws Exception {
Enumeration enu = ref.getAll();
for (int i = 0; enu.hasMoreElements(); i++) {
RefAddr addr = (RefAddr) enu.nextElement();
if (addr.getType().compareTo(addrType) == 0) {
return i;
}
}
throw new Exception("The \"" + addrType
+ "\" name/value pair was not found"
+ " in the Reference object. The reference Object is" + " "
+ ref.toString());
}
//===================加密部分 start=====================
// 加密
public String encode(String str) {
byte[] b = null;
String s = null;
try {
b = str.getBytes("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (b != null) {
/*
* 審計中對可能含有特殊字符的字段做base64編碼
* 列表中數據如果有換行符會影響顯示
* 根據RFC822規定,BASE64Encoder編碼每76個字符,還需要加上一個回車換行 部分Base64編碼的java庫還按照這個標準實行
* 換用Apache的 commons-codec.jar, Base64.encodeBase64String(byte[])得到的編碼字符串是不帶換行符的
*/
s = org.apache.commons.codec.binary.Base64.encodeBase64String(b);
}
return s;
}
// 解密
public String decode(String s) {
byte[] b = null;
String result = null;
if (s != null) {
try {
b = org.apache.commons.codec.binary.Base64.decodeBase64(s);
result = new String(b, "utf-8");
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
//===================加密部分 end=====================
}
四、修改原來的tomcat連接數據庫部分
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
<Resource name="jdbc/srw"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
maxActive="1000"
minIdle="100"
maxIdle="800"
maxWait="10000"
username="system"
password="b3JhY2xl"
url="jdbc:oracle:thin:@//192.168.26.155:1521/orcl"
testWhileIdle = "true"
testOnBorrow="true"
validationQueryTimeout="30"
validationQuery="select 1 from dual"
timeBetweenEvictionRunsMillis = "30000"
minEvictableIdleTimeMillis = "1800000"
numTestsPerEvictionRun="10"
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true"
factory="com.simp.tomcat.EncryptedDataSourceFactory"
/>
<Resource name="jdbc/sro"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
maxActive="500"
minIdle="50"
maxIdle="400"
maxWait="10000"
username="system"
password="b3JhY2xl"
url="jdbc:oracle:thin:@//192.168.26.155:1521/orcl"
testWhileIdle = "true"
testOnBorrow="true"
validationQueryTimeout="30"
validationQuery="select 1 from dual"
timeBetweenEvictionRunsMillis = "30000"
minEvictableIdleTimeMillis = "1800000"
numTestsPerEvictionRun="10"
removeAbandoned="true"
removeAbandonedTimeout="180"
logAbandoned="true"
factory="com.simp.tomcat.EncryptedDataSourceFactory"
/>
注意部分:
1、password="b3JhY2xl" 這是加密的部分,密文是由代碼裏生成密碼部分生成的。
2、連接的地方需要添加 factory="com.simp.tomcat.EncryptedDataSourceFactory" 工廠類,這樣tomcat啓動的時候纔會走你的代碼
3、tomcat啓動的時候會有一個警告,
警告: Failed to register in JMX: javax.naming.NamingException: Could not load resource factory class [Root exception is java.lang.ClassNotFoundException: com.simp.tomcat.EncryptedDataSourceFactory]
這個警告筆者也是找了許久沒有解決,雖然啓動有警告,但是對項目沒有影響,所以就這樣了。沒有處理
=============================end ===========================