记一次tomcat连接oracle数据库,密码为密文的更改
程序员文章站
2022-07-13 08:12:33
...
在实际开发中,遇到过这么一个需求,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 ===========================