现在的位置: 首页 > 综合 > 正文

spring启动时,解密配置文件的密文

2013年01月27日 ⁄ 综合 ⁄ 共 4164字 ⁄ 字号 评论关闭


场景:spring项目中,为了安全,配置文件中的部分信息设置成密文的,比如数据库密码,spring在加载这些配置文件时,需要指定相应的解密算法去解密这些配置项。
实现原理:

1.继承spring中的org.springframework.beans.factory.config.PropertyPlaceholderConfigurer类,并覆盖其中的loadProperties方法,同时需要声明locations属性,该属性是需要加载的配置文件的路径,且该属性在PropertyPlaceholderConfigurer类中定义,这里需要把它给覆盖,同时提供相应的覆盖后的set 和get 方法。

package com.jaycn.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Properties;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.io.AbstractFileResolvingResource;
import org.springframework.core.io.Resource;

/**
 *   加载properties文件的入口                    
 * @Filename PropertiesLoad.java
 *
 * @Description 
 *
 * @Version 1.0
 *
 * @Author MEISEI
 *
 * @Email 
 *       
 * @History
 *<li>Author: MEISEI</li>
 *<li>Date: 2013-5-30</li>
 *<li>Version: 1.0</li>
 *<li>Content: create</li>
 *
 */
public class PropertiesLoad extends PropertyPlaceholderConfigurer {
	
	/** Comment for <code>propertiesPersister</code> 
	 * 处理properties文件的对象
	 *  */
	private PropertiesProcessor	propertiesPersister	= new PropertiesProcessor();
	
	private Resource[]			locations;
	
	@Override
	public void setLocation(Resource location) {
		this.locations = new Resource[] { location };
	}
	
	@Override
	public void setLocations(Resource[] locations) {
		this.locations = locations;
	}
	
	@Override
	protected void loadProperties(Properties props) throws IOException {
		if (this.locations != null) {
			InputStream is = null;
			Reader reader = null;
			String filename = null;
			
			for (Resource location : this.locations) {
				is = null;
				try {
					is = location.getInputStream();
					reader = new InputStreamReader(is);
					
					filename = (location instanceof AbstractFileResolvingResource) ? location
						.getFilename() : null;
					if ((filename != null) && (filename.endsWith(".xml"))) {
						this.propertiesPersister.loadFromXml(props, is);
					} else {
						this.propertiesPersister.doLoad(props, reader);
					}
				} catch (IOException ex) {
					System.out.println("");
				} finally {
					if (is != null)
						is.close();
				}
			}
		}
	}
}


2.继承spring中的org.springframework.util.DefaultPropertiesPersister类,覆盖其中的doLoad方法,配置项的解密过程在doLoad方法中实现。

package com.jaycn.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.springframework.util.DefaultPropertiesPersister;
import org.springframework.util.StringUtils;

/**
 * 处理properties文件,并将数据库密文转换为明文
 * @Filename PropertiesProcessor.java
 *
 * @Description 
 *
 * @Version 1.0
 *
 * @Author MEISEI
 *
 * @Email
 *       
 * @History
 *<li>Author: MEISEI</li>
 *<li>Date: 2013-5-30</li>
 *<li>Version: 1.0</li>
 *<li>Content: create</li>
 *
 */
public class PropertiesProcessor extends DefaultPropertiesPersister {
	
	/** Comment for <code>decodeKeys</code>
	 * 存放properties文件中的密文项
	 *  */
	private static List<String>	DEC_VALUE_LIST	= new ArrayList<String>();
	static {
		DEC_VALUE_LIST.add("jdbc.password");
	}
	
	@Override
	protected void doLoad(Properties props, Reader reader) throws IOException {
		BufferedReader in = new BufferedReader(reader);
		String line = null;
		String nextLine = null;
		char firstChar = 0;
		
		while (true) {
			line = in.readLine();
			if (line == null) {
				return;
			}
			
			line = StringUtils.trimLeadingWhitespace(line);
			if (line.length() > 0) {
				firstChar = line.charAt(0);
				if ((firstChar != '#') && (firstChar != '!')) {
					while (endsWithContinuationMarker(line)) {
						nextLine = in.readLine();
						line = line.substring(0, line.length() - 1);
						if (nextLine != null) {
							line = line + StringUtils.trimLeadingWhitespace(nextLine);
						}
					}
					
					int separatorIndex = line.indexOf("=");
					if (separatorIndex == -1) {
						separatorIndex = line.indexOf(":");
					}
					
					String key = separatorIndex != -1 ? line.substring(0, separatorIndex) : line;
					String value = separatorIndex != -1 ? line.substring(separatorIndex + 1) : "";
					key = StringUtils.trimTrailingWhitespace(key);
					value = StringUtils.trimLeadingWhitespace(value);
					
					if (DEC_VALUE_LIST.contains(key)) {
						// ******用相应的解密算法去解密配置项******
						value = decodeValue(value);
					}
					
					props.put(unescape(key), unescape(value));
				}
			}
		}
	}
	
	/**
	 * 使用解密算法对value进行解密
	 * @param value 加密的value
	 * @return 解密的value
	 */
	private String decodeValue(String value) {
		return DesEncryptDecrypt.decode(value);
	}
}

3.在spring的配置文件中,配置读取properties文件的解析类。比如在applicationContext.xml中配置如下信息:

<!-- JDBC参数配置 -->
	<bean
		class="com.jaycn.util.PropertiesLoad">
		<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
		<property name="ignoreResourceNotFound" value="true" />
		<property name="locations">
			<list>
				<value>classpath:db.properties</value>
			</list>
		</property>
	</bean>

注意:数据库配置文件的读取应该放在配置数据库连接信息之前,不然数据库的密码为密文会导致无法连接到数据库。

抱歉!评论已关闭.