转载请注明出处:https://blog.csdn.net/l1028386804/article/details/79920338
Druid是阿里巴巴开发的一款数据库连接池,它支持对数据库密码的加密操作,今天我们就一起来实现如何利用Druid对数据库的密码进行加密操作。
其中要注意的是:
package com.lyz.crypto.rsa;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* RSA算法
* @author liuyazhuang
*
*/
public class RSAKeysUtil {
public static final String KEY_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
private static final String PUBLIC_KEY = "RSAPublicKey";
private static final String PRIVATE_KEY = "RSAPrivateKey";
public static void main(String[] args) {
Map keyMap;
try {
keyMap = initKey();
String publicKey = getPublicKey(keyMap);
System.out.println(publicKey);
String privateKey = getPrivateKey(keyMap);
System.out.println(privateKey);
} catch (Exception e) {
e.printStackTrace();
}
}
public static String getPublicKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
byte[] publicKey = key.getEncoded();
return encryptBASE64(key.getEncoded());
}
public static String getPrivateKey(Map keyMap) throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
byte[] privateKey = key.getEncoded();
return encryptBASE64(key.getEncoded());
}
public static byte[] decryptBASE64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
public static String encryptBASE64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
public static Map initKey() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map keyMap = new HashMap(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
}
运行这个类,输出的结果如下:
上边是公钥下边是私钥。
package com.lyz.dbsource.demo;
import com.alibaba.druid.filter.config.ConfigTools;
/**
* @author liuyazhuang
*
*/
public class ConfigToolsDemo {
/**
* 私钥对数据进行加密
*/
private static final String PRIVATE_KEY_STRING = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKtq3IJP5idDXZjML6I8HTAl0htWZSOO43LhZ/+stsIG50WsuW0UJ2vdrEtjvTEfJxP6N1VNrbsF9Lrsp6A4AyUwx00ZUueTlbUaX60134Di0IdQ3C4RTt5mPIbF3hUKers8csltgYR4fByvR3Eq4lt+jAolVHKmyzufukH3d3vJAgMBAAECgYBXiyW+r4t9NdxRMsaI9mZ5tncNWxwgAtOKUi/I1a4ofVoTrVitqoNPhVB+2BtBQQW2IC2uNROq1incZQxeuPxxZJgz1lnnZyHvDE3wuMZAGTcalID+5xBZ2j6fBtDnxbfIL/tIfGJrX+0mUXP2LIo242yQIlzr7RV60iuE2Ms54QJBAOqE0ycvztfxubqBWO7l8PsS3qDUv9lLBBO/Q8I+qVl4tzh+SD/13BqLuaj9eWPGPyml+faWtbmuQgBqauT23l0CQQC7HmMC0CgZS6taQxmPkXzw0XhxZ7tBZeLWl87hqc2S79P0BPX9kPukiC4LpA5xyz0CZ5azJXd2EwRsxF32GERdAkASEi4bJOnxZeUD5BewQPOyxR92kS4/VjJ4OxLDkwSFqnGj3sc+dnmBaibiSLXj5FDVqr56K97Q8gaP9aNLBWLZAkEAjwGnPBQoQUTinaZgl6fibA47VbiolU+v8L+u3iqvMVhXjcxo0DUJDXMCdeUZIQDqDLdsplfBGB1qqVHeWeGsBQJAXGNe2I510WLjMdn+olhi5ZjMr4F4oiF8TAE1Uu74FWn0sc418E7ScgXPCgpGVK0QaXo2wtDeMIoxJwm9Zh8oyg==";
// @Test
// public void demo() throws Exception {
// //密码明文,也就是数据库的密码
// String plainText = "cardiochina.net123456";
// System.out.printf(ConfigTools.encrypt(PRIVATE_KEY_STRING, plainText));
// }
public static void main(String[] args) throws Exception {
//密码明文,也就是数据库的密码
String plainText = "root";
System.out.printf(ConfigTools.encrypt(PRIVATE_KEY_STRING, plainText));
}
}
结果如下:
然后将数据库配置的链接密码改为这个输出结果如下:
jdbc.username=root
jdbc.password=EA9kJ8NMV8zcb5AeLKzAsL/8F1ructRjrqs69zM70BwDyeMtxuEDEVe9CBeRgZ+qEUAshhWGEDk9ay3TLLKrf2AOE3VBn+w8+EfUIEXFy8u3jYViHeV8yc8Z7rghdFShhd/IJbjqbsro1YtB9pHrl4EpbCqp7RM2rZR/wJ0WN48=
package com.lyz.dbsource;
import java.util.Properties;
import com.alibaba.druid.filter.config.ConfigTools;
import com.alibaba.druid.util.DruidPasswordCallback;
/**
* 数据库密码回调
* @author liuyazhuang
*
*/
public class DBPasswordCallback extends DruidPasswordCallback {
private static final long serialVersionUID = -4601105662788634420L;
/**
* password的属性
*/
private static final String DB_PWD = "password";
/**
* 数据对应的公钥
*/
public static final String PUBLIC_KEY_STRING = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCratyCT+YnQ12YzC+iPB0wJdIbVmUjjuNy4Wf/rLbCBudFrLltFCdr3axLY70xHycT+jdVTa27BfS67KegOAMlMMdNGVLnk5W1Gl+tNd+A4tCHUNwuEU7eZjyGxd4VCnq7PHLJbYGEeHwcr0dxKuJbfowKJVRypss7n7pB93d7yQIDAQAB";
@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
String pwd = properties.getProperty(DB_PWD);
if (pwd != null && !"".equals(pwd.trim())) {
try {
//这里的password是将jdbc.properties配置得到的密码进行解密之后的值
//所以这里的代码是将密码进行解密
//TODO 将pwd进行解密;
String password = ConfigTools.decrypt(PUBLIC_KEY_STRING, pwd);
setPassword(password.toCharArray());
} catch (Exception e) {
setPassword(pwd.toCharArray());
}
}
}
// public static void main(String[] args) throws Exception{
// System.out.println(ConfigTools.decrypt(PUBLIC_KEY_STRING, "fbTGHjui2zKUOBRiX/XYNvlBXTPGj4vXhOD7oh91cWvBvpf+ZsrAGDcVBwYfs2xqn5tWueC5VAI0o0nglV0R17PIata6OlVOr4hEvqID+x2nbhRBjxSfCMEwvVmdTFXahV1yuMMnLbi7FadbVuq10apTAGY1Ts5Vhuo1fNLyba4="));
// }
}
其中PasswordCallback是javax.security.auth.callback包下面的,底层安全服务实例化一个 PasswordCallback 并将其传递给 CallbackHandler 的 handle 方法,以获取密码信息。
当然,除了使用上述的方式,自己也可以对应一套加解密方法,只需要在DBPasswordCallback的 String password = ConfigTools.decrypt(PUBLIC_KEY_STRING, pwd); 替换即可。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
username=root
#回调DBPasswordCallback解密,这里的密码是你加密之后的密码!!!
password=EA9kJ8NMV8zcb5AeLKzAsL/8F1ructRjrqs69zM70BwDyeMtxuEDEVe9CBeRgZ+qEUAshhWGEDk9ay3TLLKrf2AOE3VBn+w8+EfUIEXFy8u3jYViHeV8yc8Z7rghdFShhd/IJbjqbsro1YtB9pHrl4EpbCqp7RM2rZR/wJ0WN48=
#定义初始连接数
initialSize=20
#定义最大连接数
maxActive=40
#定义最大空闲
maxIdle=20
#定义最小空闲
minIdle=1
#定义最长等待时间
maxWait=60000
注意:2、3过程中密码的设置要确定,加密、解密的最初始密码是要对应的
在自己的spring配置文件中加入下边的一句bean配置:
另外还可以直接继承自Spring提供的PropertyPlaceholderConfigurer,摘录别人一段代码大家参考一下:
public class DecryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer{
/**
* 重写父类方法,解密指定属性名对应的属性值
*/
@Override
protected String convertProperty(String propertyName,String propertyValue){
if(isEncryptPropertyVal(propertyName)){
return DesUtils.getDecryptString(propertyValue);//调用解密方法
}else{
return propertyValue;
}
}
/**
* 判断属性值是否需要解密,这里我约定需要解密的属性名用encrypt开头
* @param propertyName
* @return
*/
private boolean isEncryptPropertyVal(String propertyName){
if(propertyName.startsWith("encrypt")){
return true;
}else{
return false;
}
}
}