在使用springMVC开发web项目中,为了数据安全,数据库的用户名,密码一般都是配置在.properties文件中,相关密码尽可能进行密文保存,防止信息泄露。
本项目中,使用了druid数据库连接池,连接池的相关配置会存在在单独的文件。
然后在通过.xml配置文件引入.properties的变量,例如
比如:dbconfig.properties
###########测试环境############
url=jdbc:mysql://xxx:3306/db?useUnicode=true&characterEncoding=utf-8;autoReconnect=true
username=root
password=123456
driverClassName=com.mysql.jdbc.Driver
filters=stat
maxActive=20
initialSize=1
maxWait=60000
minIdle=10
maxIdle=15
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 'x'
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
maxOpenPreparedStatements=20
removeAbandoned=true
removeAbandonedTimeout=1800
logAbandoned=true
原先的配置扫面通过以下配置
<context:property-placeholder location="classpath:dbconfig.properties,classpath:app.properties" file-encoding="utf-8"/>
druid的数据源配置如下:
<bean id="pooledDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<property name="driverClassName" value="${driverClassName}" />
<property name="filters" value="${filters}" />
<property name="maxActive" value="${maxActive}" />
<property name="initialSize" value="${initialSize}" />
<property name="minIdle" value="${minIdle}" />
<property name="maxWait" value="${maxWait}" />
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testWhileIdle" value="${testWhileIdle}" />
<property name="testOnBorrow" value="${testOnBorrow}" />
<property name="testOnReturn" value="${testOnReturn}" />
<property name="maxOpenPreparedStatements" value="${maxOpenPreparedStatements}" />
<property name="removeAbandoned" value="${removeAbandoned}" />
<property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" />
<property name="logAbandoned" value="${logAbandoned}" />
bean>
以上的配置需要对数据库username和password进行加密,加密算法选DES。
package com.csii.util;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.security.Key;
import java.security.SecureRandom;
public class DesUtil {
private static Key key;
private static String KEY_STR = "test-key";
static {
try {
KeyGenerator generator = KeyGenerator.getInstance("DES");
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(KEY_STR.getBytes());
generator.init(secureRandom);
key = generator.generateKey();
generator = null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 对字符串进行加密,返回BASE64的加密字符串
* <功能详细描述>
*
* @param str
* @return
* @see [类、类#方法、类#成员]
*/
public static String getEncryptString(String str) {
BASE64Encoder base64Encoder = new BASE64Encoder();
System.out.println(key);
try {
byte[] strBytes = str.getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptStrBytes = cipher.doFinal(strBytes);
return base64Encoder.encode(encryptStrBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 对BASE64加密字符串进行解密
* <功能详细描述>
*
* @param str
* @return
* @see [类、类#方法、类#成员]
*/
public static String getDecryptString(String str) {
BASE64Decoder base64Decoder = new BASE64Decoder();
try {
byte[] strBytes = base64Decoder.decodeBuffer(str);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptStrBytes = cipher.doFinal(strBytes);
return new String(encryptStrBytes, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String getDecryptStringByKey(String str) {
BASE64Decoder base64Decoder = new BASE64Decoder();
try {
byte[] strBytes = base64Decoder.decodeBuffer(str);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptStrBytes = cipher.doFinal(strBytes);
return new String(encryptStrBytes, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String name = "root";
String password = "123456";
String encryname = getEncryptString(name);
String encrypassword = getEncryptString(password);
System.out.println(encryname);
System.out.println(encrypassword);
System.out.println(getDecryptString(encryname));
System.out.println(getDecryptString(encrypassword));
}
}
测试main方法输出:
com.sun.crypto.provider.DESKey@186a1
com.sun.crypto.provider.DESKey@186a1
kzaWDiA6UD8=
AfVZ4X447eg=
root
123456
提醒:因测试使用System.out.println 这种不严谨的打印日志方式,实际开发请注意规范。
当前想要更安全的加密方式,可以使用AES等其他加密也行。
PropertiesUtil配置文件:
package com.csii.util;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.util.StringUtils;
public final class PropertiesUtil extends PropertyPlaceholderConfigurer {
private Logger logger = Logger.getLogger(PropertiesUtil.class);
private static Map<String, String> ctxPropertiesMap; // 用于存放perperties中的数据
private List<String> decryptProperties; // 用于存放需要解密的key
@Override
protected void loadProperties(Properties props) throws IOException {
super.loadProperties(props);
ctxPropertiesMap = new HashMap<String, String>();
System.out.println("要加载的文件:" + props.keySet());
for (Object key : props.keySet()) {
String keyStr = key.toString();
String value = props.getProperty(keyStr);
if (decryptProperties != null && decryptProperties.contains(keyStr)) {
value = DesUtil.getDecryptString(value); // 解密
props.setProperty(keyStr, value); // 设置解密后的明文数据
System.out.println("解密后的内容:" + value);
}
ctxPropertiesMap.put(keyStr, value);
}
}
/**
* @param decryptProperties
*/
public void setDecryptProperties(List<String> decryptProperties) {
this.decryptProperties = decryptProperties;
}
/**
* Get a value based on key , if key does not exist , null is returned
*
* @param key
* @return
*/
public static String getString(String key) {
try {
return ctxPropertiesMap.get(key);
} catch (MissingResourceException e) {
return null;
}
}
/**
* 根据key获取值
*
* @param key
* @return
*/
public static int getInt(String key) {
return Integer.parseInt(ctxPropertiesMap.get(key));
}
/**
* 根据key获取值
*
* @param key
* @param defaultValue
* @return
*/
public static int getInt(String key, int defaultValue) {
String value = ctxPropertiesMap.get(key);
if (StringUtils.isEmpty(value)) {
return defaultValue;
}
return Integer.parseInt(value);
}
/**
* 根据key获取值
*
* @param key
* @param defaultValue
* @return
*/
public static boolean getBoolean(String key, boolean defaultValue) {
String value = ctxPropertiesMap.get(key);
if (StringUtils.isEmpty(value)) {
return defaultValue;
}
return new Boolean(value);
}
}
在这里插入代码片
```json
###########测试环境############
url=jdbc:mysql://xxx:3306/db?useUnicode=true&characterEncoding=utf-8;autoReconnect=true
username=kzaWDiA6UD8=
password=AfVZ4X447eg=
driverClassName=com.mysql.jdbc.Driver
filters=stat
maxActive=20
initialSize=1
maxWait=60000
minIdle=10
maxIdle=15
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 'x'
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
maxOpenPreparedStatements=20
removeAbandoned=true
removeAbandonedTimeout=1800
logAbandoned=true
<bean class="com.csii.util.PropertiesUtil">
<property name="locations">
<list>
<value>classpath:app.propertiesvalue>
<value>classpath:dbconfig.propertiesvalue>
list>
property>
<property name="decryptProperties">
<array>
<value>usernamevalue>
<value>passwordvalue>
array>
property>
bean>
配置完成后重新启动spring mvc服务,测试密文信息,是否解密生效。