<!-- 指定数据源配置文件 -->
<context:property-placeholder location="classpath:*.properties" />
以通配符【*】匹配所有properties文件。
一般来说,打包好的项目要交付给运维时,都需要将数据库的用户名和密码加密,此时以通配符来匹配,倒行不通了,因为我们需自定义解密类。
首先跑个main方法或者@Test方法 把用户名和密码加密,替换jdbc.properties里的用户名和密码,如下:
username=n5ObTJEjFBNijYQ7vtR6Og==
password=30eG52KcqRVNlWy8lt0yLw==
这样还看得出来,我就呀屎。
别说你认不出来,就算是spring也认不出来,这TM什么jb配置。
所以,得帮spring一把,偷偷帮它解密,附在耳边告诉它:是这样,&%¥@#!@¥%*&……
-_-!!
改动spring.xml的配置方式,如果只有一个jdbc.properties需要加载,那直接配置
<bean id="propertyConfigurer" class="com.xxx.xxx.util.jdbc.DecryptPropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
就可以了,如果还有其他properties配置文件要加载,那就再加上
<context:property-placeholder location="classpath:classpath:log4j.properties,classpath:redis.properties," ignore-unresolvable="true"/>
location里多个可以用逗号隔开,另外 ignore-unresolvable="true"必须加上。
至于DecryptPropertyPlaceholderConfigurer这个类,需要自己创建了,目的是为了解析jdbc配置的加密信息。
public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer{
/**
* 重写父类方法,解密指定属性名对应的属性值
*/
@Override
protected String convertProperty(String propertyName,String propertyValue){
if(isEncryptPropertyVal(propertyName)){
return DigestExampleUtil.getDecryptString(propertyValue);//调用解密方法
}else{
return propertyValue;
}
}
/**
* 判断属性是否需要解密
* @param propertyName
* @return
*/
private boolean isEncryptPropertyVal(String propertyName){
if(propertyName!=null && "username,password".contains(propertyName)){
return true;
}else{
return false;
}
}
}
DigestExampleUtil类:
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class DigestExampleUtil {
private static final String PASSWORD = "WTF";
public static void main(String[] args) throws UnsupportedEncodingException {
String content = "123456";
//加密
System.out.println("加密前:" + content);
byte[] encryptResult = encrypt(content);
String encryptResultStr = new String(Base64.encodeBase64(encryptResult));
System.out.println(encryptResultStr);
//解密
byte[] decryptFrom = Base64.decodeBase64(encryptResultStr);
byte[] decryptResult = decrypt(decryptFrom);
System.out.println("解密后:" + new String(decryptResult));
}
public static String getDecryptString(String encryptResultStr) {
String ym = "";
try {
byte[] decryptFrom = Base64.decodeBase64(encryptResultStr);
byte[] decryptResult = decrypt(decryptFrom);
ym = new String(decryptResult);
} catch (Exception e) {
e.printStackTrace();
}
return ym;
}
public static byte[] encrypt(String content) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(PASSWORD.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(byteContent);
return result; // 加密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] decrypt(byte[] content) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(PASSWORD.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
byte[] result = cipher.doFinal(content);
return result; // 加密
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
用的是AES加密,dataSource 里的 配置依旧不变,如下:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!-- 基本属性 url、user、password -->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
到此就OK了.......
#2018年6月15日18:24:55 修改#
按上面的流程,在windows下是没问题的,但Linux下却不行。
原因:SecureRandom 实现完全隨操作系统本身的內部狀態,除非調用方在調用 getInstance 方法之後又調用了 setSeed 方法;该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。(这句话我抄来的!!!)
那可咋整?
往死里整!
把上面的加密解密代码改改:
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = SecureRandom.getInstance("OJBK" );
secureRandom.setSeed(PASSWORD.getBytes());
kgen.init(128, secureRandom);
//kgen.init(128, new SecureRandom(PASSWORD.getBytes())); //← 注释了它 加上它们 ↑
SecretKey secretKey = kgen.generateKey();
如此才算大功告成,阿弥陀佛,端午安康!