当前位置: 首页 > article >正文

利用mybatis拦截器完成入库加密出库解密

在很多应用场景中,为了保证数据的安全性,我们需要对数据库中的敏感数据进行加密存储,在读取数据时再进行解密。MyBatis 是一个优秀的 Java 持久化框架,通过其拦截器机制,我们可以方便地实现入库加密和出库解密的功能。

一、MyBatis 拦截器简介

MyBatis 的拦截器机制允许我们在执行 SQL 语句的不同阶段进行干预。拦截器可以拦截的方法包括:

  1. Executor(执行器)的方法,如updatequery等。
  2. StatementHandler(语句处理器)的方法,如prepareparameterize等。
  3. ResultSetHandler(结果集处理器)的方法,如handleResultSetshandleOutputParameters等。

通过实现Interceptor接口并配置拦截器,可以在不修改业务代码的情况下,对数据库操作进行增强。

二、实现入库加密出库解密的思路

  1. 对于入库操作,在Executorupdate方法拦截中,获取要插入或更新的数据,对敏感字段进行加密后再执行数据库操作。
  2. 对于出库操作,在ResultSetHandlerhandleResultSets方法拦截中,获取查询结果集,对敏感字段进行解密后再返回给业务层。

三、具体实现步骤

(一)定义加密和解密工具类


        1. 此处省略:每个公司/企业等,使用的加密方式都有所不同,自行发挥.

(二)创建拦截器加密类


@Intercepts({
        @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)})
@Component
@Slf4j
public class SpecialInputParamInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("SpecialInputParamInterceptor拦截器执行了...");
        log.info("SpecialInputParamInterceptor拦截器执行了...");
        if (invocation.getTarget() instanceof ParameterHandler) {
            ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
            PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0];
            // 反射获取 参数对像
            Field parameterField =
                    parameterHandler.getClass().getDeclaredField("parameterObject");
            parameterField.setAccessible(true);
            Object parameterObject = parameterField.get(parameterHandler);
            if (Objects.nonNull(parameterObject)){
                if (parameterObject instanceof Map) {
                    Map<?,?> paramMap = (Map<?,?>) parameterObject;
                    for (Object value : paramMap.values()) {
                        if (value instanceof Collection) {
                            Collection<?> collection = (Collection<?>) value;
                            for (Object item : collection) {
                                if (Objects.nonNull(item)){
                                    Class<?> itemClass = item.getClass();
                                    EncryptTransaction encryptDecryptClass = AnnotationUtils.findAnnotation(itemClass, EncryptTransaction.class);
                                    if (Objects.nonNull(encryptDecryptClass)) {
                                        //加密操作
                                    }
                                }
                            }
                        }
                        break;
                    }
                }else {
                    Class<?> parameterObjectClass = parameterObject.getClass();
                    EncryptTransaction encryptDecryptClass = AnnotationUtils.findAnnotation(parameterObjectClass, EncryptTransaction.class);
                    if (Objects.nonNull(encryptDecryptClass)){
                        Field[] declaredFields = parameterObjectClass.getDeclaredFields();
                        encryptFields(declaredFields, parameterObject,null);
                    }
                }

            }
        }
        return invocation.proceed();
    }

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



    @Override
    public void setProperties(Properties properties) {

    }

    private void encryptFields(Field[] declaredFields, Object parameter, SqlCommandType sqlCommandType) throws Exception {
        for (Field field : declaredFields) {
            Annotation annotation = field.getAnnotation(EncryptTransaction.class);
            if (annotation != null) {
                field.setAccessible(true);
                Object originalValue = field.get(parameter);
                if (originalValue!= null && originalValue instanceof String) {
                    String encryptedValue = encryptValue((String) originalValue);
                    field.set(parameter, encryptedValue);
                }
            }
        }
    }

    private String encryptValue(String value) throws Exception {
        return AESUtil.encrypt(value);
    }
}

在这个拦截器中,当执行插入或更新操作时,对带有EncryptTransaction注解的对象中的敏感字段进行加密。

(三)创建结果集处理进行解密拦截器类


@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args={Statement.class})
})
@Component
@Slf4j
public class SpecialParamOutPutInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("SpecialParamOutPutInterceptor拦截器执行了...");
        log.info("SpecialParamOutPutInterceptor拦截器执行了...");
        Object result = invocation.proceed();
        if (Objects.isNull(result)){
            return null;
        }

        if (result instanceof ArrayList) {
            ArrayList resultList = (ArrayList) result;
            if (CollectionUtils.isNotEmpty(resultList) && needToDecrypt(resultList.get(0))){
                for (Object item : resultList) {
                    if (item instanceof User || item instanceof UserVo) {
                        
                            //解密操作
        }
        return result;
    }

    public boolean needToDecrypt(Object object){
        Class<?> objectClass = object.getClass();
        EncryptTransaction encryptDecryptClass = AnnotationUtils.findAnnotation(objectClass, EncryptTransaction.class);
        if (Objects.nonNull(encryptDecryptClass)){
            return true;
        }
        return false;
    }

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

    @Override
    public void setProperties(Properties properties) {

    }

    private void decryptFields(Field[] declaredFields, Object parameter) throws Exception {
        for (Field field : declaredFields) {
            Annotation annotation = field.getAnnotation(EncryptTransaction.class);
            if (annotation!= null) {
                field.setAccessible(true);
                Object originalValue = field.get(parameter);
                if (originalValue!= null && originalValue instanceof String) {
                    String decryptedValue = decryptValue((String) originalValue);
                    field.set(parameter, decryptedValue);
                }
            }
        }
    }

    private String decryptValue(String value) throws Exception {
        return AESUtil.decrypt(value);
    }
}

这个拦截器在查询结果集处理阶段,对带有EncryptTransaction注解的对象中的敏感字段进行解密。

(四)配置拦截器

在 MyBatis 的配置文件中添加拦截器配置:

<configuration>
    <plugins>
        <plugin interceptor="com.example.EncryptionInterceptor">
            <!-- 可以在这里配置拦截器的属性 -->
        </plugin>
        <plugin interceptor="com.example.DecryptionInterceptor">
            <!-- 可以在这里配置拦截器的属性 -->
        </plugin>
    </plugins>
    <!-- 其他配置 -->
</configuration>

!!!记得在实体类与字段上加自定义的注解

四、总结

通过 MyBatis 拦截器机制,我们可以轻松实现入库加密和出库解密的功能,增强了数据的安全性。在实际应用中,可以根据具体需求调整加密和解密算法,以及敏感字段的识别方式。同时,要注意拦截器的性能影响,避免过度复杂的处理逻辑导致性能下降。

以上就是利用 MyBatis 拦截器完成入库加密出库解密的一种实现方式
 

喜欢可以三连,有大哥可以赏赐,会欣喜不已,感谢!


http://www.kler.cn/a/316525.html

相关文章:

  • 本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——12使用YOLO-Bin
  • 移动端网页兼容适配方案小结
  • 【MySQL基础篇】多表查询(隐式/显式内连接、左/右外连接、自连接查询、联合查询、标量/列/行/表子查询)
  • STM32串口第一次接收数据时第一个字节丢失的问题
  • Element-plus表格使用总结
  • 基于Spring Boot的九州美食城商户一体化系统
  • 算法之搜索--最长公共子序列LCS
  • leetcode746. 使用最小花费爬楼梯,动态规划
  • Uniapp低版本的安卓不能用解决办法
  • Qt_窗口界面QMainWindow的介绍
  • Deep Guided Learning for Fast Multi-ExposureImage Fusion
  • 对接空号检测平台可以降低成本吗
  • 动手学深度学习(pytorch)学习记录32-稠密连接网络(DenseNet)[学习记录]
  • Vue | watch监听
  • IDEA Project不显示/缺失文件
  • 手机在网状态查询接口如何用PHP进行调用?
  • AWS 管理控制台
  • Apache APISIX学习(1):介绍、docker启动
  • Java是怎么处理死锁的
  • 006——队列
  • 带线无人机现身俄罗斯抗干扰技术详解
  • HTML5 Video标签的属性、方法和事件汇总,以及常用视频插件推荐
  • 深蓝学院-- 量产自动驾驶中的规划控制算法 小鹏
  • G - Merchant Takahashi / F - Useless for LIS
  • mysql学习教程,从入门到精通,TOP 和MySQL LIMIT 子句(15)
  • 本地连线上Redis访问不通