spring项目配置文件不允许出现明文密码的解决方法(jasypt使用方法)
一、前言
为了解决这个问题,可以使用jasypt
这个jar包,这个jar包可以对字符串进行加解密,项目中引入后,在配置文件中写加密后的密码即可,项目启动时这个jar包就会对密码进行解密,不影响项目正常使用。
java类中也不允许出现明文密码,也可以利用这个jar包进行加解密。
二、解决方法
1.spring项目中,在pom.xml
里引入:
<!-- https://mvnrepository.com/artifact/org.jasypt/jasypt -->
<dependency><groupId>org.jasypt</groupId><artifactId>jasypt</artifactId><version>1.9.3</version>
</dependency>
2.编写一个加解密工具类ENC_Util.java
,样例如下:
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;public class ENC_Util {private static final String SALT = "mysalt";/* jasypt-1.9.3 加解密工具类( jasypt-spring-boot-starter 是 2.1.2 )*/private static final String PBEWITHMD5ANDDES = "PBEWithMD5AndDES";private static final String PBEWITHHMACSHA512ANDAES_256 = "PBEWITHHMACSHA512ANDAES_256";public static String encryptWithMD5(String plainText) {return encryptWithMD5(plainText,SALT);}public static String decryptWithMD5(String plainText) {//自己的解密方法,解密时,需要把ENC()去掉才行if(plainText == null || plainText.length()<=5){return "";}else{plainText = plainText.substring(4,plainText.length()-1);}return decryptWithMD5(plainText,SALT);}/* Jasyp2.x 加密(PBEWithMD5AndDES)* @param plainText 待加密的原文* @param factor 加密秘钥* @return java.lang.String*/public static String encryptWithMD5(String plainText, String factor) {// 1. 创建加解密工具实例StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();// 2. 加解密配置EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();config.setAlgorithm(PBEWITHMD5ANDDES);config.setPassword(factor);encryptor.setConfig(config);// 3. 加密return encryptor.encrypt(plainText);}/* Jaspy2.x 解密(PBEWithMD5AndDES)* @param encryptedText 待解密密文* @param factor 解密秘钥* @return java.lang.String*/public static String decryptWithMD5(String encryptedText, String factor) {// 1. 创建加解密工具实例StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();// 2. 加解密配置EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig();config.setAlgorithm(PBEWITHMD5ANDDES);config.setPassword(factor);encryptor.setConfig(config);// 3. 解密return encryptor.decrypt(encryptedText);}/* Jasyp3.x 加密(PBEWITHHMACSHA512ANDAES_256)* @param plainText 待加密的原文* @param factor 加密秘钥* @return java.lang.String*/public static String encryptWithSHA512(String plainText, String factor) {// 1. 创建加解密工具实例PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();// 2. 加解密配置SimpleStringPBEConfig config = new SimpleStringPBEConfig();config.setPassword(factor);config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);// 为减少配置文件的书写,以下都是 Jasyp 3.x 版本,配置文件默认配置config.setKeyObtentionIterations( "1000");config.setPoolSize("1");config.setProviderName("SunJCE");config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");config.setStringOutputType("base64");encryptor.setConfig(config);// 3. 加密return encryptor.encrypt(plainText);}/* Jaspy3.x 解密(PBEWITHHMACSHA512ANDAES_256)* @param encryptedText 待解密密文* @param factor 解密秘钥* @return java.lang.String*/public static String decryptWithSHA512(String encryptedText, String factor) {// 1. 创建加解密工具实例PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();// 2. 加解密配置SimpleStringPBEConfig config = new SimpleStringPBEConfig();config.setPassword(factor);config.setAlgorithm(PBEWITHHMACSHA512ANDAES_256);// 为减少配置文件的书写,以下都是 Jasyp 3.x 版本,配置文件默认配置config.setKeyObtentionIterations("1000");config.setPoolSize("1");config.setProviderName("SunJCE");config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");config.setIvGeneratorClassName("org.jasypt.iv.RandomIvGenerator");config.setStringOutputType("base64");encryptor.setConfig(config);// 3. 解密return encryptor.decrypt(encryptedText);}public static void main(String[] args) {String plainText = "3s";//这个每次跑的结果不一样String encryptWithMD5Str = encryptWithMD5(plainText, SALT);//虽然不一样,这个也能正常执行String decryptWithMD5Str = decryptWithMD5(encryptWithMD5Str, SALT);System.out.println("加密前:"+plainText);System.out.println("加密后:"+encryptWithMD5Str);System.out.println("解密后:"+decryptWithMD5Str);//String encryptWithSHA512Str = encryptWithSHA512(plainText, factor);//String decryptWithSHA512Str = decryptWithSHA512(encryptWithSHA512Str, factor);//System.out.println("采用SHA512加密前原文密文:" + encryptWithSHA512Str);//System.out.println("采用SHA512解密后密文原文:" + decryptWithSHA512Str);}}
可以执行这个类的main方法,把plainText
改成待加密内容,执行后就可以生成加密后的内容;
可以修改SALT
变量,这个就是加解密用的盐值。
3.自定义一个配置文件解析类ENC_PropertyPlaceholderConfigurer
,继承PropertyPlaceholderConfigurer
,其中实现对配置文件加密内容的解密操作。样例如下:
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;import java.util.regex.Matcher;
import java.util.regex.Pattern;public class ENC_PropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {/* 将包含ENC()的value进行转换*/@Overrideprotected String convertProperty(String propertyName, String propertyValue) {//其实是 ^ENC\\(.+\\)$ //以ENC开头,包含(,中间1-N个字符,结尾是)的,就匹配成功Pattern pattern = Pattern.compile("^ENC\\\\(.+\\\\)$");Matcher matcher= pattern.matcher(propertyValue);if (matcher.find()){//如果是这样的格式,说明是加密后的,就返回解密后的内容return ENC_Util.decryptWithMD5(propertyValue);}else{//否则直接返回即可,不做处理return propertyValue;}}}
4.把自定义的解析类配置入spring的xml文件中,这样才能让项目启动时使用自己写的这个类。
以本人的项目为例,
项目启动时,一般会先加载web.xml
,其中一般会有:
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:META-INF/app_config/context/context-*.xml</param-value></context-param>
这段的意思是会加载resources
文件夹下的META-INF/app_config/context/
里面所有的以context-
开头的xml
文件;
(项目打成war包后会是项目名\\WEB-INF\\classes\\META-INF\\app_config\\context\\
)
因此,以本人的项目为例,就可以在这个路径下的xml文件里增加这样的配置:
<bean name="enc_propertyConfiger" class="com.xxx.config.ENC_PropertyPlaceholderConfigurer"><property name="ignoreResourceNotFound" value="true" /><property name="locations"><list><value>META-INF/app_config/properties/db1.properties</value><value>META-INF/app_config/properties/db2.properties</value></list></property></bean>
其中,db1.properties和db2.properties里就是数据库连接的账号密码等信息。
5.修改properties
配置文件,把其中明文密码替换为ENC(密文)
格式,样例如下:
其中密文可以执行ENC_Util.java
得到。
jdbc_driverClass=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb
jdbc_username=root
#jdbc_password=root
#用秘钥mysalt,加密就是这个,解密就是root(注意每次加密后得到的结果都不一样,不过解密得到的结果都一样)
jdbc_password=ENC(l44BhMR+f40JBsP5euOKKA==)
6.如果有的明文密码是配置在xml文件中的,那就可以用EL表达式${}
,让它读取properties中的值,例如:
<bean name="secDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><property name="url" value="${jdbc_url}" /><property name="username" value="${jdbc_username}" /><property name="password" value="${jdbc_password}" /><property name="driverClassName" value="${jdbc_driverClass}" />...
注意,因为第4步中配置了自定义配置文件解析类,所以扫描到的properties文件就会加载入项目,xml文件就可以用EL表达式获取到值。
自己要先检查下项目中是否已经配置了默认的配置文件解析类,搜索class=“org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”,如果已存在,那就把这个删掉,换成自定义的(自定义的才能加解密)
7.如果ENC_Util.java里SALT变量也不允许存在,那就可以在启动参数中增加秘钥,后续在xml文件中用${}
使用。(这个还没有试,感觉应该可以)
https://bbs.csdn.net/topics/392314029
通过 jvm 启动参数 参数 -DXXXXX, 这个XXXXX在springxml里面可以直接通过 ${XXXXX} 引用-Dmy_salt='mysalt'
然后就可以:
<bean name="enc_propertyConfiger" class="com.taikang.udp.timer.common.util.config.ENC_PropertyPlaceholderConfigurer"><property name="mySALT" value="${my_salt}" /><property name="ignoreResourceNotFound" value="true" /><property name="locations"><list><value>META-INF/app_config/properties/uat/secondaryDB.properties</value></list></property></bean>
public class ENC_PropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {//这样这个值就注入了,后续可以用private String mySALT;public void setMySALT(String mySALT){this.mySALT = mySALT;}
三、总结
1.jasypt可以对字符串进行加解密
2.spring项目中,可以把加密后的密码配置在properties文件里
3.然后可以自定义PropertyPlaceholderConfigurer
,在读取properties的时候进行解密
4.xml中,可以用${}
来使用解密后的密码等配置信息
5.java中,可以用jasypt把字符串解密后使用
6.可以在tomcat启动参数中传入全局变量,作为jasypt加解密的秘钥(如果不允许配置在代码里的话),然后在xml中使用${}
获取并注入java中使用