1. 程式人生 > >Spring + MyBatis 資料庫連線加密實現方式

Spring + MyBatis 資料庫連線加密實現方式

近期因專案需要,客戶要求資料庫使用者名稱和密碼需加密實現連線。專案實現框架SSM,上網查閱一番資料後,發現有部分資料分享的不是很完善,在此寫下隨筆,以便大家採納及提出建議。有寫的不對的地方,歡迎給予指正。

以下來介紹我的實現方式

1、配置 jdbc.properties 配置檔案,該檔案可放置在src同級目錄下,其中的SIT環境和PRD環境的引數我就給刪掉了,可以根據自身專案實際情況,決定要配置幾個引數。這裡需要注意一點,配置檔案中的使用者名稱的KEY一定不能使用username,否則會帶來不必要的麻煩,無法正確連線資料庫,具體原因還請知道的同學回覆分享下。

# 資料庫連線密文配置
# AES加密方式

#driver
jdbc.driver = oracle.jdbc.driver.OracleDriver
#url
jdbc.url = jdbc:oracle:thin:@127.0.0.1:1521/orcl
#username 
jdbc.user = test
#password fms
jdbc.password = test
#SITurl 測試環境
jdbc.SITurl = 
#SITusername 
jdbc.SITuser = 
#SITpassword 
jdbc.SITpassword = 
#PRDurl 生產環境
jdbc.PRDurl = 
#PRDusername
jdbc.PRDuser = 
#PRDpassword 
jdbc.PRDpassword = 

##加密狀態是否已加密 0-否 1-是
jdbc.isencoder = 0

2、修改 Spring 配置檔案 applicationContext-config.xml中 資料來源配置引數,如下,部分資料來源配置就沒有貼出來啦

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.user}" />
		<property name="password" value="${jdbc.password}" />
</bean>

並需要新增如下配置來讀取配置檔案,location="屬性檔案,多個之間逗號分隔",ignore-unresolvable是否忽略解析不到的屬性,如果不忽略,找不到將丟擲異常。

<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>

3、建立自己的加密工具類,和引數重寫工具類,加密工具類就百度一下有很對,加密方式可以自行百度了,這裡我使用的是AES加密方式,下面我來貼一下我的配置檔案引數重寫的工具類

/**
 * 配置檔案工具類 
 * 實現配置檔案重寫
 * 
 * @author Fyq
 *
 */
public class PropUtil {
	private static Logger logger = LoggerFactory.getLogger(PropUtil.class);

	private static Properties properties = new Properties();
	private static String filename;

	public static String getProperty(String key) {
		return properties.getProperty(key);
	}

	/**
	 * 配置檔案引數重寫
	 * 
	 * @param key
	 * @param value
	 */
	public static void setProperty(String key, String value) {
		try {
			FileInputStream inputStream = new FileInputStream(
					new File(Thread.currentThread().getContextClassLoader().getResource(filename).getPath()));
			Properties prop = new Properties();
			prop.load(inputStream);

			prop.setProperty(key, value);

			FileOutputStream outputStream = new FileOutputStream(
					new File(Thread.currentThread().getContextClassLoader().getResource(filename).getPath()));
			prop.store(outputStream, "Update '" + key + "' value");
			outputStream.flush();
			outputStream.close();
			properties.setProperty(key, value);
		} catch (FileNotFoundException e) {
			logger.error("load properties file error:" + e);
			e.printStackTrace();
		} catch (IOException e) {
			logger.error("load properties file error:" + e);
			e.printStackTrace();
		}
	}

	/**
	 * 啟動時載入properties配置檔案
	 * 
	 * @param filePath
	 */
	public static void loadFile(String filePath) {
		try {
			properties.clear();
			filename = filePath;
			properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath));
		} catch (IOException e) {
			logger.error("載入配置檔案錯誤:" + e);
			e.printStackTrace();
		}
	}
}

4、接著需要重寫 Spring容器的監聽器 ContextLoaderListener


/**
 * 重寫Spring容器的監聽器
 * 實現配置檔案屬性加密
 * @author Fyq
 *
 */
public class JdbcSafetyListener extends ContextLoaderListener {
	protected final Logger logger = LoggerFactory.getLogger(JdbcSafetyListener.class);
	// 屬性需與配置檔案的KEY保持一致
	private String[] encryptPropNames = { "jdbc.user", "jdbc.password", "jdbc.SITuser", "jdbc.SITpassword",
			"jdbc.PRDuser", "jdbc.PRDpassword" };

	/**
	 * 初始化時載入properties配置檔案
	 * 
	 * 重寫properties配置檔案,為key值加密
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		try {
			PropUtil.loadFile("jdbc.properties");
			// 配置檔案為未加密狀態
			if (PropUtil.getProperty("jdbc.isencoder").equals("0")) {
				for (String string : encryptPropNames) {
					// 獲取需加密字串
					String propertyValue = PropUtil.getProperty(string);
					// 加密密文
					String encryptValue = AESUtil.getEncryptString(propertyValue);
					log.info(string + "---->" + encryptValue);
					PropUtil.setProperty(string, encryptValue);
				}
				// 設定配置檔案加密狀態
				PropUtil.setProperty("jdbc.isencoder", "1");
			}
		} catch (Exception e) {
			log.error("引數載入失敗");
			log.debug(e.getMessage(), e);
		}
	}

	/**
	 * 最後處理的事情
	 */
	@Override
	protected void finalize() throws Throwable {
		// 關閉自動執行批處理
		super.finalize();
		log.info("引數載入成功");
	}
}

監聽器實現之後,在web.xml配置這個監聽器,啟動容器時,就會預設執行它實現的方法。

<listener>
	<listener-class>com.it.csdn.jdbcDecode.JdbcSafetyListener</listener-class>
</listener>

至此,我們的專案工程啟動後,工作域路徑\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\工程名\WEB-INF\classes\jdbc.properties中的屬性就會被重寫成密文

Linux環境下也在相關工程檔案加下可以找到,這裡就不貼出來給大家看了。

但是,我們還不能實現資料庫連線,因為資料庫user和密碼都是密文,那麼我們還需要實現使用者名稱和密碼的解密

5、實現資料庫使用者名稱和密碼的解密方式,這個時候就用到了 Spring中提供著一個 PropertyPlaceholderConfigurer ,其作用就是我們系統初始化的時候,系統自動讀取jdbc.properties配置檔案中的key value(鍵值對),然後對我們系統進行定製的初始化。

/**
 * 資料庫配置檔案解密
 * 
 * @author Fyq
 *
 */
public class EncryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
	protected final Logger logger = LoggerFactory.getLogger(EncryptPropertyPlaceholderConfigurer.class);
	// 屬性需與配置檔案的KEY保持一致
	private String[] encryptPropNames = { "jdbc.user", "jdbc.password", "jdbc.SITuser", "jdbc.SITpassword",
			"jdbc.PRDuser", "jdbc.PRDpassword" };

	@Override
	protected String convertProperty(String propertyName, String propertyValue) {
		// 如果在加密屬性名單中發現該屬性
		if (isEncryptProp(propertyName)) {
			logger.info(propertyName + "======>>" + propertyValue);
			String decryptValue = AESUtil.getDecryptString(propertyValue);
			System.out.println(decryptValue);
			return decryptValue;
		} else {
			return propertyValue;
		}

	}

	private boolean isEncryptProp(String propertyName) {
		for (String encryptName : encryptPropNames) {
			if (encryptName.equals(propertyName)) {
				return true;
			}
		}
		return false;
	}
}

PropertyPlaceholderConfigurer重寫後,需要在applicationContext-config.xml下新增如下配置來載入該配置檔案解密方式

<bean class="com.it.csdn.jdbcDecode.EncryptPropertyPlaceholderConfigurer" p:locations="classpath:jdbc.properties"></bean>

至此資料庫明文配置,密文載入就已經實現。

另外說一下,還有一種實現方式,是在配置檔案中直接配置密文的方式,可以不必使用上述步驟中的Spring容器的監聽器去重寫配置檔案。個人感覺不是很方便,說一下其中缺點吧,,直接配置密文,不利於後面其他人員的維護,資料庫使用者名稱密碼如果忘記就很尷尬,還有一點就是,windows 和 linux環境下  加密演算法不一致,導致的密文也不一樣,換環境的時候,需要來回修改配置檔案中的密文引數非常的麻煩。

希望此篇文章可以幫助到那些急需資料庫加密連線實現的人

備註:文章中部分技術實現是參考網路中一些資料。