Spring支持配置文件加解密解决方案/数据库配置加密读取解决方案

最近的项目有这样一个需求:spring配置文件中的数据源配置需要加密,也就是读取的jdbc.properties文件中的url、username、password等参数需要进行DES加密,然后在spring把参数赋值给数据源之前解密。

先来看看Spring的一段配置:


<context:property-placeholder file-encoding="UTF-8" location="classpath:/config.properties,classpath:/jdbc.properties" ignore-resource-not-found="true" />


这里的配置就是spring在项目启动时将配置文件中的属性读取到了spring容器中。此处这段配置其实就是创建PropertySourcesPlaceholderConfigurer这个类来进行的管理。各位按ctrl点击标签可以看到spring-context.xsd中的详细信息。

PropertySourcesPlaceholderConfigurer类经过一系列继承关系,实质是一个容器后管理器。debug走里面的一段代码如下:
这里写图片描述
进入这个mergeProperties()方法里面看:
这里写图片描述
可以看到localOverride这个属性是用来控制是否覆盖Spring读取的属性配置。并且下面紧跟着判断this.localProperties!=null,如果localProperties不为null的话,会读取这些配置信息到spring容易中并且覆盖spring中已存在的属性。
知道这些后,我们在来看看如下配置:

<!-- 这里的local-override="true" 就是覆盖spring容器中已存在的属性,properties-ref="dataSourceProperties" 是指定自己的properties -->
<context:property-placeholder local-override="true" properties-ref="dataSourceProperties" file-encoding="UTF-8" location="classpath:/config.properties,classpath:/jdbc.properties" ignore-resource-not-found="true" />
<!-- 这个类是我自定义的,用来解密jdbc.properties中的属性之后然后存放到Properties类中 -->
<bean id="dataSourceProperties" class="com.sh.point.spring.propertiesHandle.DataSourceProperties">
		<constructor-arg value="point.read.jdbc.username,point.read.jdbc.password,point.read.jdbc.url,point.write.jdbc.username,point.write.jdbc.password,point.write.jdbc.url"/>
	</bean>

下面是我的DataSourceProperties类:

package com.sh.point.spring.propertiesHandle;

import com.sh.point.constant.Constant;
import com.sh.point.utils.DES;

import java.io.IOException;
import java.util.Properties;

/**
 * 数据源配置参数处理
 * <p/>
 * 配置信息事先被DES加密处理,需要在此解密然后绑定到数据源
 * Created by Alvin on 2016/7/31.
 */
public class DataSourceProperties extends Properties {

    /**
     * 构造方法
     * @param propertyNames 需要解密的属性名称
     */
    public DataSourceProperties(String[] propertyNames) {
        try {
            this.load(DataSourceProperties.class.getResourceAsStream("/jdbc.properties"));
            for (String propertyName : propertyNames) {
                decrypt(propertyName);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解密
     */
    private void decrypt(String propertyName) {
        String value = DES.decrypt(this.getProperty(propertyName), Constant.ENCRYPT_KEY);
        this.setProperty(propertyName, value);
    }
    
}

然后我的数据源配置如下:

<bean id="pointRead" class="com.atomikos.jdbc.AtomikosDataSourceBean"
		  init-method="init" destroy-method="close">
		<description>mysql xa datasource</description>
		<property name="uniqueResourceName">
			<value>pointRead1</value>
		</property>
		<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
		<property name="xaProperties">
			<props>
				<prop key="user">${point.read.jdbc.username}</prop>
				<prop key="password">${point.read.jdbc.password}</prop>
				<prop key="URL">${point.read.jdbc.url}</prop>
			</props>
		</property>
		<!-- 连接池里面连接的个数? -->
		<property name="poolSize" value="3"/>
	</bean>

jdbc.properties里面的属性加密过后如下:

point.read.jdbc.url=csRbLXGXGZ65TOILxkSPCOyJksX4F0kyPy/iKeGKC0g8F4eKZFmW7ynoYjceDsrfhTtF7TC/dM0YgXAYcd9DjB5OdIulTJvHkqD458IMRC0m7pmKQb26lLj3VF0jlh+gZegrg8Y/D7o=
point.read.jdbc.username=BbeUz7wzHcE=
point.read.jdbc.password=XcZSWnefvog=

point.write.jdbc.url=csRbLXGXGZ65TOILxkSPCOyJksX4F0kyPy/iKeGKC0g8F4eKZFmW7ynoYjceDsrfhTtF7TC/dM0YgXAYcd9DjB5OdIulTJvHkqD458IMRC0m7pmKQb26lLj3VF0jlh+gZegrg8Y/D7o=
point.write.jdbc.username=BbeUz7wzHcE=
point.write.jdbc.password=XcZSWnefvog=

这样就实现了上面的需求。properties文件中的属性加密,然后spring读取的时候先由上面的自己写的DataSourceProperties类来进行解密并且存储替换,然后spring就会把解密过后的属性存放在容器,并且根据spring配置文件中的EL表达式注入到数据源中。

搞定!

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