【RuoYi-Vue-Plus】学习笔记 48 – 数据加密功能 Encrypt 源码分析

  • Post author:
  • Post category:vue




前言

前段时间,在群里大佬们讨论了关于数据存储加密的相关需求,后面就有了关于这个功能的

PR

,在

框架 5.X 版本

中,这个功能被抽取成了独立的组件,所以本文来分析一下这个功能的实现。

值得一提的是,基于这个功能,并且借助最近大火的

ChatGPT

,对于 Mybatis 的自定义插件的实现过程,我有了更进一步的了解,并且最近也在结合书籍进行 Mybatis 源码的阅读,受益匪浅,有空的话会单独再对书中的笔记进行整理分享。



参考目录



功能实现的准备知识



1、目录结构说明

在这里插入图片描述

说明 功能
EncryptField 字段加密注解 标注需要加密的字段,用于实体类字段上
AlgorithmType 算法枚举 加密注解的加密算法

algorithm()
EncodeType 编码类型枚举 加密注解的编码类型

encode()
EncryptorAutoConfiguration 加解密模块配置类 配置初始化,注册加密解密拦截器以及加密管理类
EncryptorProperties 加解密属性配置类 Yaml 配置
EncryptorManager 加密管理类 加解密功能的缓存管理以及方法调用
EncryptContext 加密上下文对象 用于 encryptor 传递必要的参数
IEncryptor 加解密接口 提供加解密接口用于自定义扩展
*Encryptor 加解密现类 根据

AlgorithmType

以及

EncodeType

提供不同的加解密实现

MybatisEncryptInterceptor
入参加密拦截器 加密功能核心实现类

MybatisDecryptInterceptor
出参解密拦截器 解密功能核心实现类



2、一些准备知识

通过上面的目录结构,其实可以知道的是,要实现加解密功能,需要重点关注的是两个 Mybatis 拦截器。

关于这一部分,我看了源码以及书,也请教了一下

ChatGPT

,下面是整理后的一些内容,了解了之后可以对这个功能先有一个大致的了解。



2.1、自定义插件如何实现?

Mybatis的自定义插件是通过实现Mybatis提供的拦截器接口实现的。

这里的拦截器接口就是指

org.apache.ibatis.plugin.Interceptor

,框架中

MybatisEncryptInterceptor

以及

MybatisDecryptInterceptor

也分别实现了这个接口。



2.2、Mybatis 拦截器的拦截点?

在这里插入图片描述

加密操作:对

ParameterHandler

进行拦截处理,拦截参数设置。

在这里插入图片描述

解密操作:对

ResultSetHandler

进行拦截处理,拦截结果集处理过程。

在这里插入图片描述



2.3、关于

@Intercepts

注解?

在这里插入图片描述



2.4、关于拦截器中的

Interceptor()

方法和

plugin()

方法?

在这里插入图片描述

在这里插入图片描述


MybatisEncryptInterceptor#plugin


在这里插入图片描述


MybatisDecryptInterceptor#intercept


在这里插入图片描述

下面通过 Debug 结合框架中的代码来分析一下这个功能。



功能调用流程分析



1、说明



1.1、数据加密配置


application.yml


在这里插入图片描述

本文使用默认配置进行说明,其他配置可以参考框架 wiki。



1.2、加密实体类


com.ruoyi.demo.domain.TestDemoEncrypt


在这里插入图片描述



1.3、Mapper(非必须)


com.ruoyi.demo.mapper.TestDemoEncryptMapper


在这里插入图片描述


由于我使用的是开发中的分支,加入了多租户插件,这里为了避免报错所以使用了插件忽略注解。



1.4、测试方法


com.ruoyi.demo.controller.TestEncryptController


在这里插入图片描述

这是框架内置的测试方法,如果想要更好地了解执行过程,也可以对此方法拆分再进行 Debug 分析。如下:

在这里插入图片描述

加密解密操作可以理解成是一个相互的过程,有加密就有解密。理解了其中一个之后,另一个其实也是类似的过程。下面分别会对这两个过程进行分析。



2、加密过程的实现分析



2.1、拦截加密实现方法


MybatisEncryptInterceptor#plugin


在这里插入图片描述



2.2、自定义加密处理器


MybatisEncryptInterceptor#encryptHandler


在这里插入图片描述



2.2.1、获取类加密字段缓存


EncryptorManager#getFieldCache


在这里插入图片描述

由于第一次调用缓存中没有,所以对所有标注

@EncryptField

注解的字段设置属性获取权限,并返回结果集。



2.2.2、属性值替换

在这里插入图片描述



2.2.3、字段加密调用过程


MybatisEncryptInterceptor#encryptField


在这里插入图片描述

根据注解以及配置创建加解密上下文对象,调用加密方法。


EncryptorManager#encrypt

在这里插入图片描述

根据加密算法创建对应的加密器,并且存入缓存。


EncryptorManager#registAndGetEncryptor


在这里插入图片描述

调用加密器的加密方法进行加密。


Base64Encryptor#encrypt


在这里插入图片描述



2.3、字段加密完成

加密完成后,返回步骤

#2.2

进行属性值替换。

在这里插入图片描述

循环替换完成后的结果:

在这里插入图片描述

所有字段加密完成后,回到拦截方法并返回目标对象。

在这里插入图片描述



3、解密过程的实现分析



3.1、拦截解密实现方法


MybatisDecryptInterceptor#intercept


在这里插入图片描述



3.2、自定义解密处理器


MybatisDecryptInterceptor#decryptHandler


在这里插入图片描述

在这里插入图片描述



3.2.1、获取类加密字段缓存

这一步和加密类似,由于加密过程中已经将字段存入缓存中,因此可以直接获取到。验证方法:

在这里插入图片描述



3.2.2、属性值替换

上一步获取到类加密字段缓存后,循环进行字段解密。

在这里插入图片描述



3.2.3、字段解密调用过程


MybatisDecryptInterceptor#decryptField


在这里插入图片描述

根据注解以及配置创建加解密上下文对象,调用解密方法。

在这里插入图片描述

如果是第一次调用,同样会根据加密算法创建对应的加密器,并且存入缓存。

在这里插入图片描述

调用加密器的解密方法进行解密。


Base64Encryptor#decrypt


在这里插入图片描述



3.3、字段解密完成

解密完成后,返回步骤

#3.2

进行属性值替换。

在这里插入图片描述

循环替换完成后的结果:

在这里插入图片描述

所有字段解密完成后,回到拦截方法并返回执行结果。

在这里插入图片描述

以上是加解密调用流程的分析。

(完)



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