MyBatis-Plus 优雅实现数据加密存储

文章目录

  • 前言
  • 一、数据库字段加解密实现
    • 1. 定义加密类型枚举
    • 2. 定义AES密钥和偏移量
    • 3. 配置定义使用的加密类型
    • 4. 加密解密接口
    • 5. 解密解密异常类
    • 6. 加密解密实现类
      • 6.1 AES加密解密实现类
      • 6.2 Base64加密解密实现类
    • 7. 实现数据库的字段保存加密与查询解密处理类
    • 8. MybatisPlus配置类
  • 二、数据库字段加密解密的使用
    • 1. 创建实体类
    • 2. 数据保存示例
    • 3. 数据查询示例


前言

本文将基于Mybatis-Plus讲述如何在数据的源头存储层保障其安全。我们都知道一些核心私密字段,比如说密码,手机号等在数据库层存储就不能明文存储,必须加密存储保证即使数据库泄露了也不会轻易曝光数据。


本文实现效果参考 plasticene-boot-starter-parent,更多信息在下面链接。

Github地址:https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent

当然也可以参考 mybatis-mate 为 mp 企业级模块,旨在更敏捷优雅处理数据。

Gitee地址:https://gitee.com/baomidou/mybatis-mate-examples

一、数据库字段加解密实现

1. 定义加密类型枚举

默认提供基于base64和AES加密算法,当然也可以自定义加密算法。

public enum Algorithm {BASE64,AES
}

2. 定义AES密钥和偏移量

@Data
@ConfigurationProperties(prefix = "ptc.encrypt")
public class EncryptProperties {/*** 加密算法 {@link Algorithm}*/private Algorithm algorithm = Algorithm.BASE64;/*** aes算法需要秘钥key*/private String key = "8iUJAD805IHO2vog";/*** aes算法需要一个偏移量* AES算法的偏移量长度必须为16字节(128位)*/private String iv = "cUTd1U+yxk8Dl6Cg";}

AES的密钥和偏移量的生成可访问:AES 密钥在线生成器

若使用RSA,密钥对的生成可访问:在线生成非对称加密公钥私钥对

3. 配置定义使用的加密类型

这里我们使用aes加密算法:

  • application.yml
ptc:encrypt:algorithm: aes

4. 加密解密接口

public interface EncryptService {/*** 加密算法* @param content* @return*/String encrypt(String content);/*** 解密算法* @param content* @return*/String decrypt(String content);}

5. 解密解密异常类

  • BizException.java
/*** 业务异常类*/
@Data
public class BizException extends RuntimeException {private Integer code;public BizException() {super();}public BizException(String message) {super(message);}public BizException(Integer code, String message) {super(message);this.code = code;}}

6. 加密解密实现类

6.1 AES加密解密实现类

@Slf4j
public class AESEncryptService implements EncryptService {@Resourceprivate EncryptProperties encryptProperties;@Overridepublic String encrypt(String content) {try {SecretKeySpec secretKey = new SecretKeySpec(encryptProperties.getKey().getBytes(StandardCharsets.UTF_8), Constants.AES);byte[] enCodeFormat = secretKey.getEncoded();SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, Constants.AES);IvParameterSpec iv = new IvParameterSpec(encryptProperties.getIv().getBytes(StandardCharsets.UTF_8));Cipher cipher = Cipher.getInstance(Constants.AES_CBC_CIPHER);cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);byte[] valueByte = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(valueByte);} catch (Exception e) {log.error("加密失败:", e);throw new BizException("加密失败");}}@Overridepublic String decrypt(String content) {try {byte[] originalData = Base64.getDecoder().decode(content.getBytes(StandardCharsets.UTF_8));SecretKeySpec secretKey = new SecretKeySpec(encryptProperties.getKey().getBytes(StandardCharsets.UTF_8), Constants.AES);byte[] enCodeFormat = secretKey.getEncoded();SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, Constants.AES);IvParameterSpec iv = new IvParameterSpec(encryptProperties.getIv().getBytes(StandardCharsets.UTF_8));Cipher cipher = Cipher.getInstance(Constants.AES_CBC_CIPHER);cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);byte[] valueByte = cipher.doFinal(originalData);return new String(valueByte);} catch (Exception e) {log.error("解密失败:", e);throw new BizException("解密失败");}}
}

6.2 Base64加密解密实现类

public class Base64EncryptService implements EncryptService {@Overridepublic String encrypt(String content) {try {return Base64.getEncoder().encodeToString(content.getBytes(StandardCharsets.UTF_8));} catch (Exception e) {throw new RuntimeException("encrypt fail!", e);}}@Overridepublic String decrypt(String content) {try {byte[] asBytes = Base64.getDecoder().decode(content);return new String(asBytes, StandardCharsets.UTF_8);} catch (Exception e) {throw new RuntimeException("decrypt fail!", e);}}
}

7. 实现数据库的字段保存加密与查询解密处理类

接下来就可以基于加密算法,扩展 MyBatis 的 BaseTypeHandler 对实体字段数据进行加密解密

public class EncryptTypeHandler<T> extends BaseTypeHandler<T> {@Resourceprivate EncryptService encryptService;@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, encryptService.encrypt((String)parameter));}@Overridepublic T getNullableResult(ResultSet rs, String columnName) throws SQLException {String columnValue = rs.getString(columnName);//有一些可能是空字符return StrUtil.isBlank(columnValue) ? (T)columnValue : (T)encryptService.decrypt(columnValue);}@Overridepublic T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {String columnValue = rs.getString(columnIndex);return StrUtil.isBlank(columnValue) ? (T)columnValue : (T)encryptService.decrypt(columnValue);}@Overridepublic T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {String columnValue = cs.getString(columnIndex);return StrUtil.isBlank(columnValue) ? (T)columnValue : (T)encryptService.decrypt(columnValue);}
}

8. MybatisPlus配置类

把EncryptService实现类注入到容器中

@Configuration
@MapperScan("com.chh.mapper")
@EnableConfigurationProperties({EncryptProperties.class})
public class MybatisPlusConfig {@Resourceprivate EncryptProperties encryptProperties;// 分页插件@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));return interceptor;}@Beanpublic EncryptTypeHandler encryptTypeHandler() {return new EncryptTypeHandler();}@Bean@ConditionalOnMissingBean(EncryptService.class)public EncryptService encryptService() {Algorithm algorithm = encryptProperties.getAlgorithm();EncryptService encryptService;switch (algorithm) {case BASE64:encryptService = new Base64EncryptService();break;case AES:encryptService = new AESEncryptService();break;default:encryptService = null;}return encryptService;}}

二、数据库字段加密解密的使用

1. 创建实体类

  • 在实体类上加上 @TableName(value = "表名", autoResultMap = true)
  • 在需要加密的属性上加上 @TableField(value = "字段", typeHandler = EncryptTypeHandler.class)
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName(value = "app_account_login", autoResultMap = true)
public class AppAccountLogin implements Serializable {private static final long serialVersionUID = 1L;/*** 主键*/@TableId(value = "id", type = IdType.AUTO)private Integer id;/*** 名称*/@TableField("name")private String name;/*** 登录账号*/@TableField("login_account")private String loginAccount;/*** 登录密码*/@TableField(value = "login_password", typeHandler = EncryptTypeHandler.class)private String loginPassword;/*** 激活状态*/@TableField("enabled")private Boolean enabled;/*** 创建时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")@TableField(fill = FieldFill.INSERT)private Date createTime;}

2. 数据保存示例

AppAccountLogin appAccountLogin = new AppAccountLogin();
appAccountLogin.setName("test");
appAccountLogin.setLoginAccount("123456789");
appAccountLogin.setLoginPassword("abc123456");
appAccountLoginService.save(appAccountLogin);

保存结果:

请添加图片描述

3. 数据查询示例

System.out.println(appAccountLoginService.getById(4));

查询结果:

AppAccountLogin(id=4, name=test, loginAccount=123456789, loginPassword=abc123456, enabled=true, createTime=Fri Feb 02 10:02:41 CST 2024)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/696846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Selenium安装与配置

文章目录 一、selenium安装1. Python环境准备&#xff1a;2. 安装Selenium&#xff1a;3. 浏览器驱动安装&#xff1a;4. 验证安装&#xff1a; 二、常见问题1. Selenium版本与浏览器驱动程序不兼容&#xff1a;2. 浏览器驱动程序路径未正确设置&#xff1a; Selenium是一个用于…

2024年1月手机市场行业分析:苹果手机份额骤降,国产高端手机成功逆袭!

小米Ultra发布。 一方面&#xff0c;我们有望看到国产手机再一次超越自己的决心&#xff0c;继续创新追逐高端&#xff1b;另一方面&#xff0c;我们也不得不正视目前手机市场所面临的危机状态。 2024年1月的线上手机市场远不如去年。根据鲸参谋数据显示&#xff0c;今年1月京…

Java面试题之分布式/微服务篇

经济依旧不景气啊&#xff0c;如此大环境下Java还是这么卷&#xff0c;又是一年一次的金三银四。 兄弟们&#xff0c;你准备好了吗&#xff1f;冲冲冲&#xff01;欧里给&#xff01; 分布式/微服务相关面试题解 题一&#xff1a;CAP理论&#xff0c;BASE理论题二&#xff1a;…

【2024软件测试面试必会技能】Postman(1): postman的介绍和安装

Postman的介绍 Postman 是一款谷歌开发的接口测试工具,使API的调试与测试更加便捷。 它提供功能强大的 Web API & HTTP 请求调试。它能够发送任何类型的HTTP 请求 (GET, HEAD, POST, PUT..)&#xff0c;附带任何数量的参数 headers。 postman是一款支持http协议的接口调试…

springboot整合mybatisPlus超级详细

springboot整合mybatis-plus超级详细 一、环境二、springboot整合myBatisPlus2.1新建2.2 添加Mybatis-plus和mysql依赖2.3 修改配置文件2.4 新建包和文件2.5 新建表2.6 创建实体类2.7 创建Mapper接口2.8 创建Service接口2.9 创建Service实现类2.10 增删改查 MyBatis-Plus&#…

C# Onnx 使用onnxruntime部署实时视频帧插值

目录 介绍 效果 模型信息 项目 代码 下载 C# Onnx 使用onnxruntime部署实时视频帧插值 介绍 github地址&#xff1a;https://github.com/google-research/frame-interpolation FILM: Frame Interpolation for Large Motion, In ECCV 2022. The official Tensorflow 2…

四.QT5工具安装和环境变量的配置

1.以管理员身份运行安装包 2.登录qt账号&#xff0c;点击【next】 3.选中同意 4.选择安装目录&#xff0c;注意不能有中文和空格 5.勾选 64位 mingw。点击【next】&#xff0c;等待安装完成 6.配置环境变量

为什么很多人选用QT开发,有哪些应用实例?

在软件开发领域&#xff0c;Qt框架作为一种跨平台的C应用程序开发框架&#xff0c;近年来受到越来越多开发者的青睐。这主要得益于其卓越的跨平台性能、丰富的功能库、开发效率以及社区支持。以下将通过详实的分析&#xff0c;从不同角度探讨为什么很多人改用QT开发&#xff0c…

力扣645. 错误的集合(排序,哈希表)

Problem: 645. 错误的集合 文章目录 题目描述思路复杂度Code 题目描述 思路 1.排序 1.对nums数组按从小到大的顺序排序; 2.遍历数组时若判断两个相邻的元素则找到重复元素&#xff1b; 3.记录一个整形变量prev一次置换当前位置元素并与其作差&#xff0c;若差等于2着说明缺失的…

Mysql索引操作

1、索引语法 2、慢查询日志 慢查询日志记录了所有执行时间超过指定参数&#xff08; long_query_time &#xff0c;单位&#xff1a;秒&#xff0c;默认 10 秒&#xff09;的所有 SQL 语句的日志。 MySQL 的慢查询日志默认没有开启&#xff0c;我们可以查看一下系统变量 slo…

【2024软件测试面试必会技能】Appium自动化(5):元素定位工具

常用元素定位工具使用 uiautomatorviewer定位工具&#xff1a; 元素定位主要用来获取元素信息&#xff0c;获取元素信息后才能用appium提供的相关API去识别和操作元素。 谷歌在AndroidSDK中&#xff0c;提供了元素定位工具uiautomatorviewer&#xff0c;该工具可在android-s…

三opencv源码解压及环境变量配置

1.双击opencv-3.4.6-vc14-vc15.exe 2.选择解压的路径&#xff0c;点击【extract】 3.设计环境变量

从零学习Linux操作系统第二十七部分 shell脚本中的变量

一、什么是变量 变量的定义 定义本身 变量就是内存一片区域的地址 变量存在的意义 命令无法操作一直变化的目标 用一串固定的字符来表示不固定的目标可以解决此问题 二、变量的类型及命名规范 环境级别 export A1 在环境关闭后变量失效 退出后 关闭 用户级别&#xff…

《初阶数据结构》尾声

目录 前言&#xff1a; 《快速排序&#xff08;非递归&#xff09;》: 《归并排序》&#xff1a; 《归并排序&#xff08;非递归&#xff09;》&#xff1a; 《计数排序》&#xff1a; 对于快速排序的优化&#xff1a; 分析&#xff1a; 总结&#xff1a; 前言&#xff1a…

新疆营盘古城及古墓群安防舱体实施方案

3 总体布局 3.1设计原则 3.1.1执行有效的国家标准、国家军用标准和行业标准&#xff1b; 3.1.2满足指标要求&#xff1b; 3.1.3采用通用化、模块化设计&#xff0c;提高设备可维修性&#xff1b; 3.1.4采用人机工程学知识进行设计&#xff0c;充分考虑安全性。 3.2 总体…

51单片机学习(3)-----独立按键控制LED的亮灭状态

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步了。 目录 一. 器件介绍及实验原理 1.独立按键 &#xff08;1&#xff09;独…

外包干了3个月,技术退步明显

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

Linux之用户和用户组的深入了解

目录 一、简介 1.1、用户&#xff1a; 1.2、用户组 1.3、UID和GID 1.3、用户账户分类 查看用户类别 超级用户root(0) 程序用户(1~499) 普通用户(500~65535) 二、用户 2.1、添加新的用户账号&#xff1a;useradd 2.2、删除账号&#xff1a;userdel 有-r与没有-r区别…

运维07:堡垒机

什么是跳板机 跳板机就是一台服务器而已&#xff0c;运维人员在使用管理服务器的时候&#xff0c;必须先连接上跳板机&#xff0c;然后才能去操控内网中的服务器&#xff0c;才能登录到目标设备上进行维护和操作 开发小张 ---> 登录跳板机 ---> 再登录开发服务器 测试…

贷齐乐系统最新版SQL注入(无需登录绕过WAF可union select跨表查询)

一、环境 已上传资源&#xff08;daiqile&#xff09; 二、代码解释 1.1Request 不管get请求还是post请求都可以接收到 1.2过滤的还挺多 1.3第二个WAF把数据分为两个了一个Key一个value&#xff0c;全是explode的功劳 1.4submit是if进入的前提 很明显走进来了 1.5那我们在这…