配置文件密码用jasypt加密

我们一般都写在yml或者properties文件中。

有没有一种办法,在配置文件中写密文,程序启动后自动解密,再使用这个解密后的密码进行连数据库或者redis?

jasypt就实现了这个功能。

https://github.com/ulisesbocchio/jasypt-spring-boot

这是jasypt的地址,上面有详细的使用说明和例子。目前版本已经更新到3.0.2

参照说明,我们看怎么使用。

目录

1,引入依赖

2,yml文件配置jasypt属性

3,用jasypt加密,在yml填写加密后的密码


1,引入依赖

<!-- jasypt方式一 -->
		<dependency>
			<groupId>com.github.ulisesbocchio</groupId>
			<artifactId>jasypt-spring-boot-starter</artifactId>
			<version>3.0.2</version>
		</dependency>
		
		<!-- jasypt方式二 -->
		<!-- <dependency>
			<groupId>com.github.ulisesbocchio</groupId>
			<artifactId>jasypt-spring-boot</artifactId>
			<version>3.0.2</version>
		</dependency> -->

2种方式引入依赖包。

第一种是你的springboot应用使用了@SpringBootApplication or @EnableAutoConfiguration注解就可以这样引入。

如果没有使用上面的注解,就用第二种方式。并且还需要在你的启动类上加注解:

@Configuration
@EnableEncryptableProperties

package com.example.gate;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;


//使用jasypt的第二种方式.如果你没用到@SpringBootApplication 或  @EnableAutoConfiguration就必须用下面2个注解,才能正常使用jasypt
//@Configuration
//@EnableEncryptableProperties

//@EnableCircuitBreaker
@ComponentScan(basePackages = "com.example")
@EnableDiscoveryClient
@SpringBootApplication
public class GateApplication {

	public static void main(String[] args) {
		SpringApplication.run(GateApplication.class, args);
	}

	

}

其实还有更高级的用法,可以指定哪几个配置文件用jasypt。

//使用jasypt的第二种方式.如果你没用到@SpringBootApplication 或  @EnableAutoConfiguration就必须用下面2个注解,才能正常使用jasypt
//@Configuration
//@EnableEncryptableProperties

//具体指定配置文件的用法,其他配置文件不受jasypt影响
//@Configuration
//@EncryptablePropertySources({@EncryptablePropertySource("classpath:encrypted.properties"),
//                             @EncryptablePropertySource("classpath:encrypted2.properties")})

//@EnableCircuitBreaker
@ComponentScan(basePackages = "com.example")
@EnableDiscoveryClient
@SpringBootApplication
public class GateApplication {

	public static void main(String[] args) {
		SpringApplication.run(GateApplication.class, args);
	}

	

}

 这个看你具体需要了。

2,yml文件配置jasypt属性

#jasypt加密配置
jasypt:
  encryptor:
    password: miyao
    algorithm: PBEWITHHMACSHA512ANDAES_256
#    property:
#      prefix: "ENC@["
#      suffix: "]"

这是我给的一个配置。

其中秘钥password是必须自己定义的。其他都可以不配置,因为有默认的配置:

KeyRequiredDefault Value
jasypt.encryptor.passwordTrue-
jasypt.encryptor.algorithmFalsePBEWITHHMACSHA512ANDAES_256
jasypt.encryptor.key-obtention-iterationsFalse1000
jasypt.encryptor.pool-sizeFalse1
jasypt.encryptor.provider-nameFalseSunJCE
jasypt.encryptor.provider-class-nameFalsenull
jasypt.encryptor.salt-generator-classnameFalseorg.jasypt.salt.RandomSaltGenerator
jasypt.encryptor.iv-generator-classnameFalseorg.jasypt.iv.RandomIvGenerator
jasypt.encryptor.string-output-typeFalsebase64
jasypt.encryptor.proxy-property-sourcesFalsefalse
jasypt.encryptor.skip-property-sourcesFalseempty list

3,用jasypt加密,在yml填写加密后的密码

先说填写密码的格式:

#jasypt加密后的密码
mypass:
  pass1: ENC(NfA+LtBfc26xLiHLb0EGXeNfU9TaE2tQIt7X94DrodPcUKV/tnTKQLz7bcLSM3i0)

面必须用ENC()包起来,这样jasypt才能识别出来这个密码需要解密再传给应用程序。

这个密码怎么获取呢?

方式有很多,

方法一:写个工具类,把jasypt加密的过程写出来,执行后得到密码。

方法二:写个controller,注入jasypt的加密对象,执行加密,把密码打印或者返回到页面

方法三:jasypt提供了加密的命令,

https://github.com/ulisesbocchio/jasypt-spring-boot

具体看上面的链接。这个其实意义不大。

 

我自己把前两种方式的代码贴出来:

工具类:


package com.example.gate.util;

import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;

/**
 * Jasypt用于在配置文件中写加密后的密码,只要配上秘钥,读入系统中的就是解密后的正确密码。
 * 这个工具类主要是用于实验Jasypt的加密和解密.
 * 把yml中对Jasypt的配置写到代码里而已。
 * 
 * 实际使用Jasypt时,只需pom引入依赖,yml中配置相关项(秘钥等),然后把加密后的密码写入你需要配置的地方(yml文件。。。)
 * 程序启动后,会自动解密(如果程序不能正常解密,那你的系统启动就有问题了,比如数据库连不上,redis连不上等,都是密码不正确的错)
 * 我们也可以写个controller把yml配置文件中的密码打印出来,这个打印的肯定不是你写的加密的字符串而是解密后的正确密码。
 * 整个解密的过程是交给Jasypt做的。加密的过程是我们提前加密得到密文,写到yml配置文件中的。但是必须有ENC()这个标识。
 * 
 * 
 * @author lsy
 *
 */
public class JasyptUtil {

	public static void main(final String[] args) {

		String miyao = "miyao";// 秘钥字符串
		String pass = "123456";// 待加密的明文密码
		try {
			StringEncryptor stringEncryptor = JasyptUtil.getInstance(miyao);
			String mima = stringEncryptor.encrypt(pass);
			System.out.println("【" + pass + "】被加密成【" + mima + "】");

			String jiemi = stringEncryptor.decrypt(mima);
			System.out.println("【" + mima + "】被解密成【" + jiemi + "】");

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static StringEncryptor stringEncryptor = null;//org.jasypt.encryption.StringEncryptor对象

	public static StringEncryptor getInstance(String miyao) throws Exception {
		if(miyao==null||miyao.trim().equals("")) {
			System.out.println("秘钥不能为空!");
			throw new Exception("org.jasypt.encryption.StringEncryptor秘钥不能为空!");
		}
		if (stringEncryptor == null) {
			PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
			SimpleStringPBEConfig config = new SimpleStringPBEConfig();
			config.setPassword("miyao");// 这个秘钥必须是我们自己定义
			config.setAlgorithm("PBEWITHHMACSHA512ANDAES_256");
			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);

			stringEncryptor = encryptor;
		}
		return stringEncryptor;
	}

}

执行main方法打印:

【123456】被加密成【AAM7i7RkQeSDOf1iiAbYIDlfAGbJNch3jVu9KNqPLlwlHS4LFO3Sx22bTipeay5h】
【AAM7i7RkQeSDOf1iiAbYIDlfAGbJNch3jVu9KNqPLlwlHS4LFO3Sx22bTipeay5h】被解密成【123456】
注意,一个同样的密码和秘钥,每次执行加密,密文都是不一样的。但是解密是没问题的。

controller执行:

package com.example.gate.controller;


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import org.jasypt.encryption.StringEncryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * jasypt测试
 * 
 * @author lsy
 *
 */
@RestController
@RequestMapping("/jasypt")
public class PrintPassInYmlController {

	@Value("${spring.cloud.client.ip-address}")
	private String ip;
	
	@Value("${spring.application.name}")
	private String servername;
	
	@Value("${server.port}")
	private String port;
	
	
	@Autowired
	StringEncryptor stringEncryptor;
	
	@Value("${mypass.pass1}")
	private String pass1;//yml中定义的是密文
	
	
	//查看程序跑起来后,yml中的密码是否是明文
	@RequestMapping(value = "/viewPass1",method = RequestMethod.GET)
    @ResponseBody
    public String viewPass1(){
		DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String dateStr=LocalDateTime.now().format(df);
        
        String mess="viewPass ! 查看mypass.pass1的值是["+pass1+"]。response form  ["+servername+":"+ip+":"+port+"]"+"..."+dateStr;
        return mess;
        
    }
	
	/**
	 * 用jasypt把一个密码加密(秘钥用yml中定义的)
	 * @param param
	 * @return
	 */
	@RequestMapping(value = "/jasyptEncode",method = RequestMethod.GET)
    @ResponseBody
    public String jasyptEncode(@RequestParam(required=false) String param){
		System.out.println("jasyptEncode接收请求参数为==="+param); 
		DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String dateStr=LocalDateTime.now().format(df);
        
        String newpass=stringEncryptor.encrypt(param);
        String mess="jasyptEncode ! 把["+param+"] 加密成["+newpass+"]。response form  ["+servername+":"+ip+":"+port+"]"+"..."+dateStr;
        return mess;
        
    }
	
	
	/**
	 * 用jasypt把一个密文解密,参数是密文,返回解密后的明文(使用的秘钥还是yml中定义的)
	 * 
	 * 使用post请求是因为密码有特殊字符,所以用post请求体传值
	 * 
	 * @param param
	 * @return
	 */
	@RequestMapping(value = "/jasyptDecode",method = RequestMethod.POST)
    @ResponseBody
    public String jasyptDecode(@RequestBody String param){
		System.out.println("jasyptDecode接收请求参数为==="+param); 
		DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String dateStr=LocalDateTime.now().format(df);
		
        Map hm=new HashMap();
        hm.put("uname", "lsy");
        String realpass=stringEncryptor.decrypt(param);
        hm.put("upass", realpass);
        
        String mess="jasyptDecode ! 把["+param+"] 解密成["+realpass+"]。response form  ["+servername+":"+ip+":"+port+"]"+"..."+dateStr;
		System.out.println(mess);
		
        return "jasyptDecode response==="+hm.toString();
    }
	
}

应用跑起来后,查看yml中mypass.pass1的值:

 

我加密一个密码:

为了验证解密,我把上面的密文再发到解密的请求中:

 

注意header的Content-Type要用text/plain

 

这几种方式都能获取密文,然后我们就配置到yml中就可以了。

另外说一下ENC()这个标识是可以改的,比如我先改成ENC@[],只要按以下设置即可。其他的基本上就用默认的就行。

#jasypt加密配置
jasypt:
  encryptor:
    password: miyao
    algorithm: PBEWITHHMACSHA512ANDAES_256
    property:
      prefix: "ENC@["
      suffix: "]"

 

另一个需要关心的就是秘钥的存放了。秘钥是个字符串,写在配置文件或者写在代码都可以。

 


版权声明:本文为lushuaiyin原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。