記一次tomcat連接oracle數據庫,密碼爲密文的更改

在實際開發中,遇到過這麼一個需求,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 ===========================

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章