利用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 拦截器完成入库加密出库解密的一种实现方式
 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值