一、数据加密和脱敏

数据加密和数据脱敏都是保护数据安全的方法,但是它们的目的和方法不同。

  数据加密是一种将数据转换为加密形式的技术,通过使用密钥对数据进行加密,以使其对未经授权的人员不可读取。加密后的数据只能通过使用相应的密钥进行解密才能恢复其原始形式。加密技术通常用于保护机密性和防止未经授权的访问,例如在进行互联网交易或传输敏感数据时。

数据脱敏是一种对敏感数据进行变形或替换的技术,以使其在保留数据价值的同时去除敏感信息,从而保护数据隐私。脱敏技术通常用于匿名化或去标识化数据,以便在数据共享或数据分析中保护个人隐私。脱敏可以采用多种方法,如替换、屏蔽、截断、打乱等,以减少数据暴露的风险。

  因此,加密通常用于保护数据的机密性,而脱敏则用于保护数据的隐私性。

源码地址:

二、MybatisPlus方式

2.1、导入依赖,加密算法使用hutool包提供的AES

<dependencies>
<!--Hutool工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.3</version>
</dependency>
<!--Mybatis-Plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!--SpringBoot-Web开发-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--MySQL连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

2.2、添加数据库加解密handler,指明加解密字段类型

package com.zhixi.handlers;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
* @Description
* @Author Huicong She
* @Date 2022/8/5 11:36
*
*/

/**
* @ClassName EncryptHandler
* @Author zhangzhixi
* @Description 数据库字段加解密handler,JdbcType.VARCHAR:表示该处理器处理的数据类型
* @Date 2023-02-26 20:01
* @Version 1.0
*/
@MappedJdbcTypes(JdbcType.VARCHAR)
public class EncryptHandler extends BaseTypeHandler<String> {
/**
* 线上运行后勿修改,会影响已加密数据解密
*/
private static final byte[] KEYS = "shc987654321camp".getBytes(StandardCharsets.UTF_8);

/**
* 设置参数
*/
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
if (StringUtils.isEmpty(parameter)) {
ps.setString(i, null);
return;
}
AES aes = SecureUtil.aes(KEYS);
String encrypt = aes.encryptHex(parameter);
ps.setString(i, encrypt);
}

/**
* 获取值
*/
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
return decrypt(rs.getString(columnName));
}

/**
* 获取值
*/
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return decrypt(rs.getString(columnIndex));
}

/**
* 获取值
*/
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return decrypt(cs.getString(columnIndex));
}

public String decrypt(String value) {
if (null == value) {
return null;
}
return SecureUtil.aes(KEYS).decryptStr(value);
}
}

2.3、指明自定义类型包处理器路径

#自定义类型处理器包路径
mybatis-plus.type-handlers-package=com.zhixi.handlers

2.4、在需要加密存储的数据库表字段上添加typeHandler,并指定使用的处理器:autoResultMap = true

package com.zhixi.pojo;

import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.zhixi.handlers.EncryptHandler;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
* @TableName user
*/
@TableName(value = "user",autoResultMap = true)
@Data
public class User implements Serializable {
/**
* 主键ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 用户名
*/
@TableField(value = "username")
private String username;

/**
* 密码
*/
@TableField(value = "password")
private String password;

/**
* 姓名
*/
@TableField(value = "name")
private String name;

/**
* 年龄
*/
@TableField(value = "age")
private Integer age;

/**
* 邮箱
*/
private String email;

/**
* 住址
*/ @TableField(value = "address", typeHandler = EncryptHandler.class)
private String address;
/**
* 版本号,用于乐观锁
*/
@TableField(value = "version")
private Integer version;

/**
* 创建时间
*/
@TableField(value = "create_time", fill = FieldFill.INSERT)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
// 对入参进行格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
// 对出参进行格式化
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;


/**
* 更新时间
*/
@TableField(value = "update_time", fill = FieldFill.UPDATE)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;

/**
* 删除状态,0表示未删除,1表示已删除
*/
@TableField(value = "deleted")
private Integer deleted;

/**
* 创建时间,使用MyBatis Plus自动填充功能
*/
@TableField(value = "create_at", fill = FieldFill.INSERT)
private String createAt;

/**
* 更新时间,使用MyBatis Plus自动填充功能
*/
@TableField(value = "update_at", fill = FieldFill.UPDATE)
private String updateAt;


@TableField(exist = false)
private static final long serialVersionUID = 1L;
}

2.5、测试

 1、添加用户,验证住址字段是否加密

{
"username": "zhangsan",
"password": "123456",
"name": "张三",
"age": 30,
"email": "1820712542@qq.com",
"address": "北京市丰台区",
"version": 1,
"createTime": "2022-02-27 00:00:00",
"updateTime": "2022-02-28 04:30:00",
"deleted": 0
}

SpringBoot整合Mybatis、MybatisPlus对数据库字段进行加密/脱敏_Mybatis

数据库保存的数据:

  这里说明一下,我为了演示,没有对密码字段进行加密操作,也就是没有意义

  实际的业务中肯定也不会通过这种可逆的方式,密码保存在数据库中,不能通过查询/解密获取到实际的值。

SpringBoot整合Mybatis、MybatisPlus对数据库字段进行加密/脱敏_mybatis-plus_02

2、查询用户,验证地址字段是否解密

 

SpringBoot整合Mybatis、MybatisPlus对数据库字段进行加密/脱敏_SpringBoot_03

三、Mybatis方式(推荐,通用)


实现逻辑:

  • 1、定义个注解作用域为类的属性上,用于标识这个属性需要加密或解密。
  • 2、实现mybatis拦截器添加加解密逻辑。
  • 3、加解密逻辑:判断如果是新增和更新操作拿到该注解属性的原值进行加密,如果是查询操作就拿到数据库值反向解密。

下面进行测试的是:对地址字段进行加密,对邮箱字段进行脱敏

3.1、引入依赖

<!--为了下载依赖-->
<properties>
<java.version>1.8</java.version>
</properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<!--对数据库字段进行加密、脱敏-->
<dependency>
<groupId>com.gitee.china-zhz</groupId>
<artifactId>privacy-spring-boot-starter</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
<!--SpringBoot-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--数据库连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--SpringBoot整合Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

3.2、在实体类上面加上注解

@FieldDesensitize(fillValue = "*"):脱敏

@FieldEncrypt:加密

package com.zhixi.pojo;

import cn.zhz.privacy.annotation.FieldDesensitize;
import cn.zhz.privacy.annotation.FieldEncrypt;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
* @TableName user
*/
@Data
public class User implements Serializable {
/**
* 主键ID
*/
private Long id;
/**
* 用户名
*/
private String username;

/**
* 密码
*/
@FieldEncrypt
private String password;

/**
* 姓名
*/
private String name;

/**
* 年龄
*/
private Integer age;

/**
* 邮箱
*/ @FieldDesensitize(fillValue = "*")
private String email;

/**
* 地址
*/ @FieldEncrypt
private String address;

/**
* 版本号,用于乐观锁
*/
private Integer version;

/**
* 创建时间
*/
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
// 对入参进行格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
// 对出参进行格式化
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;


/**
* 更新时间
*/
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;

/**
* 删除状态,0表示未删除,1表示已删除
*/
private Integer deleted;

/**
* 创建时间,使用MyBatis Plus自动填充功能
*/
private String createAt;

/**
* 更新时间,使用MyBatis Plus自动填充功能
*/
private String updateAt;

private static final long serialVersionUID = 1L;
}

3.3、测试

插入数据:看地址字段是否加密

SpringBoot整合Mybatis、MybatisPlus对数据库字段进行加密/脱敏_mybatis-plus_04

db:

SpringBoot整合Mybatis、MybatisPlus对数据库字段进行加密/脱敏_java_05

查询数据:看邮箱字段展示是否脱敏、地址字段是否解密

SpringBoot整合Mybatis、MybatisPlus对数据库字段进行加密/脱敏_SpringBoot_06