定制化开发微服务SpringBoot整合Jasypt加密工具

文章目录

一、Jasypt介绍

Jasypt是Java工具包,定制化开发能支持对密码的哈希加密,定制化开发对文本和二进制数据的定制化开发对称加解密,还能集成SpringBoot定制化开发项目对配置文件中的密定制化开发钥进行加密存储。

定制化开发引入依赖如下:

<!-- https://mvnrepository.com/artifact/com.github.ulisesbocchio/jasypt-spring-boot-starter --><dependency>    <groupId>com.github.ulisesbocchio</groupId>    <artifactId>jasypt-spring-boot-starter</artifactId>    <version>3.0.4</version></dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

二、Jasypt手动使用

2.1 定制化开发密码加密场景

定制化开发用户注册账户的时候需定制化开发要输入密码,定制化开发我们将密码加密后保存定制化开发到数据库中,定制化开发保证用户的敏感数据的安全性。当用户再次登录的时候,我们需要将登录密码和注册时保存的密文密码进行比对,只有比对一致才能完成登录。

密码加密工具类主要有三个,它们都是实现了PasswordEncryptor接口,下面我们逐步来看。

@Slf4j@RestControllerpublic class SignController {    private final BasicPasswordEncryptor basicPasswordEncryptor = new BasicPasswordEncryptor();    private String encryptedPassword = null;    @GetMapping("/signup/{password}")    public String signup(@PathVariable String password){        log.info("用户注册密码为:{}", password);        encryptedPassword = basicPasswordEncryptor.encryptPassword(password);        log.info("用户注册密码加密后为:{}", encryptedPassword);        return encryptedPassword;    }    @GetMapping("/signin/{password}")    public String signin(@PathVariable String password){        log.info("用户登录密码为:{}", password);        if(basicPasswordEncryptor.checkPassword(password, encryptedPassword)){            log.info("用户登录成功!");            return "success";        }        log.info("用户登录失败!");        return "fail";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

启动项目后,我们首先注册用户密码localhost:8080/signup/123456,就能得到密文5b32ygn5pbBvphjIKco6X8Z2VfWqwEUw,并将其保存到类变量中暂存,当我们再次登录localhost:8080/signin/123456,就能登录成功了。相反的,如果登录时密码随意输错,就会登录失败。

2022-10-11 15:41:57.038  INFO 26268 --- [nio-8080-exec-1] c.e.myapp.controller.SignController      : 用户注册密码为:1234562022-10-11 15:41:57.039  INFO 26268 --- [nio-8080-exec-1] c.e.myapp.controller.SignController      : 用户注册密码加密后为:5b32ygn5pbBvphjIKco6X8Z2VfWqwEUw2022-10-11 15:42:07.405  INFO 26268 --- [nio-8080-exec-3] c.e.myapp.controller.SignController      : 用户登录密码为:1234562022-10-11 15:42:07.406  INFO 26268 --- [nio-8080-exec-3] c.e.myapp.controller.SignController      : 用户登录成功!2022-10-11 15:42:12.767  INFO 26268 --- [nio-8080-exec-4] c.e.myapp.controller.SignController      : 用户登录密码为:1234572022-10-11 15:42:12.767  INFO 26268 --- [nio-8080-exec-4] c.e.myapp.controller.SignController      : 用户登录失败!
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

那么这种加密方式是什么呢?我们可以打开BasicPasswordEncryptor的源码,看到类上面的注释:

  • Algorithm: MD5.
  • Salt size: 8 bytes.
  • Iterations: 1000.

意思就是使用的MD5这种哈希算法,并且使用8字节(64位)的盐值,迭代计算1000次得到的密文。

除了使用如上的BasicPasswordEncryptor工具之外,还有StrongPasswordEncryptor工具类,它的加密登记更加的安全:

  • Algorithm: SHA-256.
  • Salt size: 16 bytes.
  • Iterations: 100000.

如果这些加密算法都不能满足你的要求,就可以使用ConfigurablePasswordEncryptor来自定义加密工具类ConfigurablePasswordEncryptor,可以设置自己需要使用的算法。

总结:

接口类PasswordEncryptor主要有如下三个实现类:

  • BasicPasswordEncryptor,使用MD5算法;
  • StrongPasswordEncryptor,使用SHA-256算法;
  • ConfigurablePasswordEncryptor,可自定义指定哈希算法;

哈希算法是不可逆的,因此只有加密encryptPassword和检查checkPassword两个方法。

2.2 文本加密场景

用户的手机号、身份证号等敏感信息在存储的时候需要进行加密,但是这些敏感数据在需要使用的时候是需要明文解密的,因此不适合使用2.1节的哈希算法,而是使用对称加密的形式。

文本加密工具类主要有三个,它们都是实现了TextEncryptor接口,下面我们逐步来看。

@Slf4j@RestControllerpublic class TextController {    private static final BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor();    private static final String SECRET = "hello";    private String encryptedText = null;    static {        basicTextEncryptor.setPassword(SECRET);    }    @GetMapping("/encryptText/{plainText}")    public String encryptText(@PathVariable String plainText){        log.info("用户输入明文:{}", plainText);        encryptedText = basicTextEncryptor.encrypt(plainText);        log.info("用户加密密文:{}", encryptedText);        return encryptedText;    }    @GetMapping("/decryptText")    public String decryptText(){        String plainText = basicTextEncryptor.decrypt(encryptedText);        log.info("用户原始明文:{}", plainText);        return plainText;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

项目启动后,我们分别访问localhost:8080/encryptText/hello进行加密,访问localhost:8080/decryptText进行解密。

2022-10-11 15:52:36.949  INFO 21652 --- [nio-8080-exec-1] c.e.myapp.controller.TextController      : 用户输入明文:hello2022-10-11 15:52:36.950  INFO 21652 --- [nio-8080-exec-1] c.e.myapp.controller.TextController      : 用户加密密文:u/qYluhyFpyOA6xMD3z3JA==2022-10-11 15:52:46.345  INFO 21652 --- [nio-8080-exec-2] c.e.myapp.controller.TextController      : 用户原始明文:hello
  • 1
  • 2
  • 3

我们同样打开BasicTextEncryptor可以看到它的加密原理:

  • Algorithm: PBEWithMD5AndDES.
  • Key obtention iterations: 1000.

同样的,我们可以使用安全性更高的StrongTextEncryptor

  • Algorithm: PBEWithMD5AndTripleDES.
  • Key obtention iterations: 1000.

还有安全性更高的AES256TextEncryptor

  • Algorithm: PBEWithHMACSHA512AndAES_256".
  • Key obtention iterations: 1000.

2.3 数值加密场景

如果需要对整数或者小数进行加密,就可以分别使用IntegerNumberEncryptor接口和DecimalNumberEncryptor接口的实现类。同样的,这种场景的加密也都是对称加密,用法完全一样。

IntegerNumberEncryptor:主要用来对整数进行加解密。

  • BasicIntegerNumberEncryptor
    • Algorithm: PBEWithMD5AndDES.
    • Key obtention iterations: 1000.
  • StrongIntegerNumberEncryptor
    • Algorithm: PBEWithMD5AndTripleDES.
    • Key obtention iterations: 1000.
  • AES256IntegerNumberEncryptor
    • Algorithm: PBEWithHMACSHA512AndAES_256.
    • Key obtention iterations: 1000.

DecimalNumberEncryptor:主要用来对小数进行加解密。

  • BasicDecimalNumberEncryptor
    • Algorithm: PBEWithMD5AndDES.
    • Key obtention iterations: 1000.
  • StrongDecimalNumberEncryptor
    • Algorithm: PBEWithMD5AndTripleDES.
    • Key obtention iterations: 1000.
  • AES256DecimalNumberEncryptor
    • Algorithm: PBEWithHMACSHA512AndAES_256.
    • Key obtention iterations: 1000.

2.4 数据加密场景

暂未遇到需要加密二进制数据的业务场景,此处略过,使用方法可以参考官网。

三、Jasypt整合SpringBoot

SpringBoot应用中有很多和密码都是存储在配置文件中的,我们需要将它们以密文的方式存储起来。

# 服务器配置server:  port: 8080# Spring配置spring:  # 数据源配置  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&&serverTimezone=Asia/Shanghai&&useSSL=false    username: root    # 此处是密码的密文,要用ENC()进行包裹    password: ENC(KZeGx0ixuy4UrBp1HuhiDNnKB0cJr0cW)# mybatis配置mybatis:  mapper-locations: classpath:mapper/*Mapper.xml# 加密配置jasypt:  encryptor:    # 指定加密密钥,生产环境请放到启动参数里面    password: your-secret    # 指定解密算法,需要和加密时使用的算法一致    algorithm: PBEWithMD5AndDES    # 指定initialization vector类型    iv-generator-classname: org.jasypt.iv.NoIvGenerator
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

如上是对数据库密码进行加密存储,密文是怎么的来的?可以写一个测试类,使用第二节介绍的内容自己手动加密。

@Slf4jpublic final class JasyptUtils {    /**     * 加密使用密钥     */    private static final String PRIVATE_KEY = "lybgeek";    private static BasicTextEncryptor basicTextEncryptor = new BasicTextEncryptor();    static {        basicTextEncryptor.setPassword(PRIVATE_KEY);    }    /**     * 私有构造方法,防止被意外实例化     */    private JasyptUtils() {    }    /**     * 明文加密     *     * @param plaintext 明文     * @return String     */    public static String encrypt(String plaintext) {        log.info("明文字符串为:{}", plaintext);        // 使用的加密算法参考2.2节内容,也可以在源码的类注释中看到        String ciphertext = basicTextEncryptor.encrypt(plaintext);        log.info("密文字符串为:{}", ciphertext);        return ciphertext;    }    /**     * 解密     *     * @param ciphertext 密文     * @return String     */    public static String decrypt(String ciphertext) {        log.info("密文字符串为:{}", ciphertext);        ciphertext = "ENC(" + ciphertext + ")";        if (PropertyValueEncryptionUtils.isEncryptedValue(ciphertext)) {            String plaintext = PropertyValueEncryptionUtils.decrypt(ciphertext, basicTextEncryptor);            log.info("明文字符串为:{}", plaintext);            return plaintext;        }        log.error("解密失败!");        return "";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
@Slf4jpublic class JasyptUtilsTest {    @Test    public void testEncrypt(){        String plainText = "Glrs@1234";        String ciperText = JasyptUtils.encrypt(plainText);        log.info("加密后的密文为:{}", ciperText);    }    @Test    public void testDecrypt(){        String ciperText = "KZeGx0ixuy4UrBp1HuhiDNnKB0cJr0cW";        String plainText = JasyptUtils.decrypt(ciperText);        log.info("解密后的明文为:{}", plainText);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

经过如上的配置,启动项目,如下从数据库获取数据的应用逻辑就能正常使用了。

@Slf4j@RestControllerpublic class HelloController {    @Autowired    UserMapper userMapper;    @GetMapping("/getHello")    public String getHello(){        log.info("myapp works!");        List<User> users = userMapper.listUsers();        return users.toString();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
@Mapperpublic interface UserMapper {    List<User> listUsers();}
  • 1
  • 2
  • 3
  • 4
<mapper namespace="com.example.myapp.mapper.UserMapper">    <select id="listUsers" resultType="com.example.myapp.bean.User">        select zu.user_id userId, zu.user_name userName, zu.age age, zu.user_email userEmail from zx_user zu;    </select></mapper>
  • 1
  • 2
  • 3
  • 4
  • 5

四、生成环境启动

生产环境密钥作为启动参数:

java -jar -Djasypt.encryptor.password=your-secret
  • 1

无、参考文档

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发