Mybatis拦截器安全加解密MySQL数据实战

【Mybatis】基于Mybatis拦截器+注解,实现敏感数据自动加解密 我司最近在做等保,要求数据库里面的手机号、微信号、身份证号等等这些在数据库中都不能是明文,所以需要把数据库中的涉及到这些的加密保存,但是查询和保存的接口传参不受影响,之前业务给前端返回是什么样子依然保持不变,这样前端不受影响。 阅读详情

需求背景

  • 公司为了通过一些金融安全指标(政策问题)和防止数据泄漏,需要对用户敏感数据进行加密,所以在公司项目中所有存储了用户信息的数据库都需要进行数据加密改造。包括Mysql、redis、mongodb、es、HBase等。
  • 因为在项目中是使用springboot+mybatis方式连接数据库进行增删改查,并且项目是中途改造数据。所以为了不影响正常业务,打算这次改动尽量不侵入到业务代码,加上mybatis开放的各种拦截器接口,所以就以此进行改造数据。
  • 本篇文章讲述如何在现有项目中尽量不侵入业务方式进行Mysql加密数据,最后为了不降低查询性能使用了注解,所以最后还是部分侵入业务。

Mybatis拦截器

  • Mybatis只能拦截指定类里面的方法:Executor、ParameterHandler、StatementHandler、ResultSetHandler。
    • Executor:拦截执行器方法;
    • ParameterHandler:拦截参数方法;
    • StatementHandler:拦截sql构建方法;
    • ResultSetHandler:拦截查询结果方法;
  • Mybatis提供的拦截器接口Interceptor
public interface Interceptor {

  Object intercept(Invocation invocation) throws Throwable;

  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }

  default void setProperties(Properties properties) {
    // NOP
  }
}
复制代码
- Object intercept():代理对象都会调用的方法,这里可以执行自定义拦截处理;
- Object plugin():可以用于判断拦截器执行类型;
- void setProperties():指定配置文件的属性;
复制代码
  • 自定义拦截器中除了要实现Interceptor接口,还需要添加@Intercepts注解指定拦截对象。@Intercepts注解需配合@Signature注解使用
  • @Intercepts注解可以指定多个@Signature,type指定拦截类,method指定拦截方法,args拦截方法里的参数类型。
/**
 * @author Clinton Begin
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
  Signature[] value();
}

/**
 * @author Clinton Begin
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
  Class<?> type();
  String method();
  Class<?>[] args();
}
复制代码

案例实战

  • 依据上述的mybatis拦截器的使用,下面就把实战案例代码提供一下。

Mybatis自定义拦截器

  • 在业务代码里用户信息是以明文传递的,所以为了不改动业务代码,那么需要拦截器在插入或查询数据库数据前先加密,查询结果解密操作。
  • 首先搭建一个springboot的项目,这里指定两个mybatis拦截器,一个拦截请求参数,一个拦截响应数据,并把拦截器注入到spring容器内。
/**
 * 对mybatis入参进行拦截加密
 * @author zrh
 */
@Slf4j
@Component
@Intercepts(@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}))
public class MybatisEncryptInterceptor implements Interceptor {

    @Resource
    private com.mysql.web.mybatis.Interceptor.MybatisCryptHandler handler;

    @Override
    public Object intercept (Invocation invocation) {
        return invocation;
    }

    @SneakyThrows
    @Override
    public Object plugin (Object target) {
        if (target instanceof ParameterHandler) {
            // 对请求参数进行加密操作
            handler.parameterEncrypt((ParameterHandler) target);
        }
        return target;
    }

    @Override
    public void setProperties (Properties properties) {
    }
}
复制代码
  • 注意:ResultSetHandler对象对增删改方法没有拦截,需要增加Executor对象;
/**
 * 对mybatis查询结果进行拦截解密,并对请求参数进行拦截解密还原操作
 * @author zrh
 */
@Slf4j
@Component
@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}),
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
})
public class MybatisDecryptInterceptor implements Interceptor {

    @Resource
    private MybatisCryptHandler handler;

    @Override
    public Object intercept (Invocation invocation) throws Exception {
        // 获取执行mysql执行结果
        Object result = invocation.proceed();
        if (invocation.getTarget() instanceof Executor) {
            // 对增删改操作方法的请求参数进行解密还原操作
            checkEncryptByUpdate(invocation.getArgs());
            return result;
        }
        // 对查询方法的请求参数进行解密还原操作
        checkEncryptByQuery(invocation.getTarget());
        // 对查询结果进行解密
        return handler.resultDecrypt(result);
    }

    @Override
    public Object plugin (Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties (Properties properties) {
    }

    /**
     * 对请求参数进行解密还原操作
     * @param target
     */
    private void checkEncryptByQuery (Object target) {
        try {
            final Class<?> targetClass = target.getClass();
            final Field parameterHandlerFiled = targetClass.getDeclaredField("parameterHandler");
            parameterHandlerFiled.setAccessible(true);
            final Object parameterHandler = parameterHandlerFiled.get(target);
            final Class<?> parameterHandlerClass = parameterHandler.getClass();
            final Field parameterObjectField = parameterHandlerClass.getDeclaredField("parameterObject");
            parameterObjectField.setAccessible(true);
            f
如何使用Mybatis的拦截器实现数据加密与解密 也许应对当前的业务,看了该文章满足了当下需求,我们目前只看到了什么是 Mybatis 拦截器,怎样简单使用,拦截器的其他用法以及其他很多为什么都没有解决,关注公众号,回复“人迹罕至” 读完文章 「程序猿为什么要看源码」后 ,我不会满足眼前的这些基本应用,我会有诸多疑问,我们要实现数据加密,进入数据库的字段不能是真实的数据,但是返回来的数据要真实可用,所以我们需要针对 Parameter 和 ResultSet 两种类型处理,同时为了更灵活的使用,我们需要自定义注解。如果需要实现自定义的拦截器,只需要实现。 阅读详情

相关推荐

Mybatis数据加密解密

类注解,将注解放在实体类上/*** 需要加解密的类注解*/@Inherited字段注解,将注解放在实体字段上/*** 加密字段注解*/@Inherited有了这两个注解,我们可以在我们可以标记我们要处理的实体和实体中的字段。

lvyuanj的专栏 3195

基于MyBatis拦截器实现数据字段自动加解密的工程实践

在数据安全领域,数据库字段加密是保护敏感信息(如用户隐私、金融数据)的核心技术之一。其基本原理是在数据持久化到数据库前进行加密,查询时再解密,确保磁盘存储的为密文,内存中处理的为明文。这项技术的核心价值在于实现安全与开发的平衡,它通过无侵入的方式将加密逻辑与业务代码解耦,极大提升了系统的可维护性和安全策略的灵活性。在Java生态中,MyBatis拦截器为实现这一机制提供了优雅的切入点,通过拦截SQL执行生命周期,可自动完成指定字段的加解密。典型的应用场景包括用户手机号、身份证号等敏感信息的存储。本文以AES

weixin_33938733的博客 413

MyBatis-Plus字段加解密实战:保障MySQL敏感数据安全

数据安全是应用开发的核心议题,尤其在处理用户手机号、身份证等敏感信息时,防止数据泄露至关重要。在应用层对敏感字段进行加密存储是一种常见的安全实践,其原理是在数据写入数据库前进行加密,读取时再解密,从而确保即使数据库被非法访问,敏感信息也不易被直接获取。这项技术的核心价值在于将安全策略与业务逻辑解耦,提升代码的可维护性和安全性。在实际的工程实践中,ORM框架如MyBatis-Plus通过其拦截器或TypeHandler机制,能够以声明式、无侵入的方式自动完成字段的加解密,极大地简化了开发流程。然而,实现过程中

weixin_34161083的博客 489

Spring切面加解密MySQL数据实战

/@Slf4j@Aspect@Componenttry {// 判断当前参数是否需要加密和加密字段下标是否为null// 加密操作// 解密判断操作log.error(“MybatisCryptAspect加密方法异常”, e);/**查询结果解密@return*//**查询参数加密@return*/复制代码在实际项目,直接使用字符串作为入参和查询结果的业务代码不多,其中又只定位需要加解密的特定字段,这样其实就更少了。

D1561691的博客 728

Mybatis拦截器+注解实现敏感数据自动加解密,告别业务代码侵入

在数据安全日益重要的今天,数据库字段级加密是保护用户身份证号、手机号等敏感信息的常见手段。其核心原理是在数据持久化层面对特定字段进行透明加解密,从而在存储层面保障数据安全,避免明文泄露风险。从技术实现角度看,这通常涉及加密算法(如AES)、密钥管理和ORM框架的扩展机制。Mybatis作为Java领域广泛使用的持久层框架,其提供的插件(拦截器)机制,允许开发者在SQL执行的关键生命周期节点插入自定义逻辑,这为实现自动化、非侵入式的数据处理提供了强大的技术基础。结合自定义注解,可以优雅地标记需要处理的实体类字

深未来技术 483

LangChain开发避坑指南:为什么Pylance总提示‘无法解析导入‘?实测7种修复方案

本文深入解析了在VS Code中使用LangChain开发时,Pylance频繁提示‘无法解析导入’的根本原因——Python解释器与语言服务器的环境路径不一致。文章提供了从基础排查到深度配置的7种实测修复方案,包括切换解释器、配置extraPaths、使用pyrightconfig.json等,旨在帮助开发者彻底解决此问题,提升AI应用开发效率。

weixin_28826521的博客 444

CMIP6数据处理及在气候变化、水文、生态等领域中的应用

CMIP6、Biome-BGC、生态、气候变化、气象、水文、气候模式、植被、生态模式、遥感、极端气候、降水、WRF模式、动力降尺度、RCM、大气环流模型、贝叶斯模型、、降尺度

PhyliciaFelicia的博客 1544

Camera 基础知识

Raw Sensor输出的Data格式为Raw,图像的效果处理使用BB端的ISP,BB端接收Raw data后进行一系列的图像处理(OB,Shading,AWB,Gamma,EE,ANR等),效果方面由BB端控制,需要针对不同的模组进行效果调试,Raw sensor是目前的主流,数据量比YUV Sensor小(RAW10 格式的sensor 1个pixel 10个bit)使用平台ISP处理,能支持较大的size。不过,相位对焦并不是那么完美,它对光线的要求就比较高,在弱光拍摄环境下,相位对焦就无能威力了。

手机-手表蓝牙开发工程师的博客 3062

【深度学习基础】Temporal Fusion Transformer

从下向上看:全连接(Dense) → ELU(指数线性激活函数(比relu好点,有利于模型收敛)) → 全连接(Dense) → 门控线性单元(Gate)(Gated Linear Units (GLUs)) → Layernorm。:一方面,它可以进行静态上下文变量和动态变量的融合,另一方面,通过门控进行了特征选择操作,门控体现在GLU(门控线性单元)中,用了sigmoid控制信息的通过程度,具有良好的适应性,能够自动选择有效信息,自适应地调整网络复杂性。输入:主输入,可选的上下文向量c。

weixin_41838721的博客 1224

国外无人机蜂群作战典型战例及发展趋势

参与袭击的无人机为简易组装的固定翼飞机,采用小排量活塞发动机和手机GPS通信模块零件,机翼为轻木加泡沫板混合结构,尾梁为铝合金方管,主要依靠胶带粘接,以上全部配件均可在商用市场买到,成本较低,可在短时间内装配完成。③战场纵深短、瞬时性强。蜂群作战的参战数量显著增加,这一方面得益于无人机技术的飞速发展使得廉价无人机可以大量生产和仿制,另一方面凭借迅速发展的投放和回收技术以及集群控制技术,使得无人机蜂群可在极短时间内实现编队饱和攻击,在快速消耗敌方高价值防空武器系统的同时,保证己方物资系统的突防概率。

renhongxia1的博客 2479

STM32实战:滑模观测器与PLL锁相环融合的FOC无感控制精解

本文深入解析了STM32平台下结合滑模观测器(SMO)与PLL锁相环的无感FOC控制技术。通过实战案例详细介绍了PLL锁相环在消除SMO高频抖振、提升角度跟踪精度方面的关键作用,并分享了工程调参技巧、C语言实现细节及系统联调方法,为电机控制开发者提供了一套完整的解决方案。

weixin_30838873的博客 189

某二级支行网络的设计与实现——配置脚本(1)

【代码】某二级支行网络的设计与实现——配置脚本(1)

u010311846的博客 577

systermverilog中for循环中的fork join执行情况分析

仅为本人学习记录,如有错误感谢指正!

qq_63807221的博客 1461

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

上一篇: SkyWalking Java Agent 配置初始化流程分析
下一篇: Java异步编程的核心类:FutureTask
superjava_
博客等级 码龄5年 254粉丝 81原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值