网站数据库安全,Wordpress排名插件,h5自助建站系统,中国建筑装饰网设计师联盟前言
最近在搞个安全需求#xff0c;需要对敏感字段做加密存储。于是#xff0c;#xff0c;于是我就躺了个坑。
方案梳理
方案一#xff1a;基于Mybatis的拦截器Interceptor
我的第一个反应其实是基于Mybatis的拦截器Interceptor机制实现#xff0c;在设置参数的时候…前言
最近在搞个安全需求需要对敏感字段做加密存储。于是于是我就躺了个坑。
方案梳理
方案一基于Mybatis的拦截器Interceptor
我的第一个反应其实是基于Mybatis的拦截器Interceptor机制实现在设置参数的时候对参数进行拦截并加密而在查询的时候对返回值进行解密。当然不管是那种方案都需要对敏感字段进行标记。 实现可参考mybatis-plus实现数据字段加解密
PS: 该博客可以满足绝大部分场景了但Map、ListString没有考虑。不过这也是基于Interceptor的弊端就是你需要考虑更多的细节。
方案二基于Mybatis的TypeHandler
Mybatis支持针对特定字段的类型进行特殊处理这为字段的加解密提供了可能。关于Mybatis的TypeHandler大家可以看看官方的【类型处理器typeHandlers】 简单来说就一句话在执行SQL之前对入参和返回值进行处理。
而Mybatis本身通过这个进行类型转换。想知道其自带了多少TypeHandler可以看看mybatis的这个包org.apache.ibatis.type
基于这个特点我们就可以利用来实现字段的加解密功能。为了不影响那些不需要加解密的字段我们就必须要在在特定的字段上进行指定。
对于select可以通resultMap标签来指定例如
resultMap typeorg.apache.ibatis.submitted.rounding.User idusermap2result columnroundingMode propertyroundingMode typeHandlerorg.apache.ibatis.type.EnumTypeHandler/
/resultMap对于入参则不需要区分是什么语句只需要在取值的时候指定就行:
insert idinsert2 insert into users2 (id, name, funkyNumber, roundingMode) values(#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler org.apache.ibatis.type.EnumTypeHandler})
/insert这便是我们基于Mybatis实现加解密的理论基础。
MybatisPlus优雅实现加解密
众所周知MybatisPlus并不准备取代Mybatis而是对Mybatis的增强增加一些便于使用的特性。 以TypeHandler为例
TableName(value foo_user, autoResultMap true)
public class User {private String username;/*** 通过mp的TableField注解指定TypeHandler。* PS: 这里的MyTypeHandler是需要自己实现TypeHandler接口的哈。* 由于我这里没有逻辑就不给大伙看了*/TableField(typeHandler MyTypeHandler.class)private String mobile;
}public interface UserMapper extends BaseMapperUser {
}就这样我们就完成了MybatisPlus官方源码缩写为mp的配置。我们可以很方便的调用UserMapper#insert方法通过上面指定的typeHandler来执行我们需要对mobile字段的加密逻辑。 调用UserMapper#selectById方法也会自动的执行typeHandler的解密逻辑。后者通过TableName的autoResultMap true配置生效他会自动向Mybatis中注入一个ResultMap其效果等同于我们在xml文件中书写的resultMap。
感兴趣的同学可以参考这篇文章 基于MybatisPlus的实现
MybatisPlus真的这么优雅丝滑
事情并没有这么简单前面我们大致了解了Mybatis本身提供的TypeHandler组件也知道MybatisPlus的基于TypeHandler为我们提供的简单易用的优雅的使用方式。可是各位同学想过没有我们自己在xml中写的SQL呢MybatisPlus也能如此智能、方便地达到我们的目的呢 很显然不能够。我们在xml中写update语句没有指定typeHandler的话是MybatisPlus也是无能为力的。这是因为他不能掌握我们的SQL了更不能为我们添加指定typeHandler。这对于select语句也是如此 事实上MybatisPlus在其注解之上也有说明
Documented
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public interface TableField {/*** JDBC类型 (该默认值不代表会按照该值生效),* 只生效于 mp 自动注入的 method,* 建议配合 {link TableName#autoResultMap()} 一起使用* p* {link ResultMapping#jdbcType} and {link ParameterMapping#jdbcType}** since 3.1.2*/JdbcType jdbcType() default JdbcType.UNDEFINED;/*** 类型处理器 (该默认值不代表会按照该值生效),* 只生效于 mp 自动注入的 method,* 建议配合 {link TableName#autoResultMap()} 一起使用* p* {link ResultMapping#typeHandler} and {link ParameterMapping#typeHandler}** since 3.1.2*/Class? extends TypeHandler typeHandler() default UnknownTypeHandler.class;
}
Documented
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
public interface TableName {/*** 是否自动构建 resultMap 并使用,* 只生效于 mp 自动注入的 method,* 如果设置 resultMap 则不会进行 resultMap 的自动构建并注入,* 只适合个别字段 设置了 typeHandler 或 jdbcType 的情况** since 3.1.2*/boolean autoResultMap() default false;
}清楚明白地写着只支持自动生成的方法。
要命的是我们在实际项目中不可能只使用单表查询这样一来我们就不得不自己写SQL。然而当你使用MybatisPlus这么方便愉快地写代码的时候你还会深入源码看注释吗还会深入源码了解其实现原理吗不你不会本来就是因为懒才使用MybatisPlus的。这就使得很多同学陷入迷茫排查问题不知所措为什么就是不生效为什么这个方法可以想想都崩溃
总结
MybatisPlus的TableField注解的部分字段只使用于自动生成的方法因为它可以掌控和改造目标SQL的生成。本质上还是在使用Mybatis的功能。例如指定typeHandler、javaType。Mybatis本身提供了TypeHandler组件我们可以基于这个来实现敏感字段的加解密。
后记
给大家个建议如果你想偷懒而且你的项目足够简单简单到通过单表操作就能够解决问题那么可以使用MybatisPlus。否则我不建议大家使用MybatisPlus尤其不建议使用这种半吊子的功能。实际上MybatisPlus主要还是希望基于Mybatis给大家提供一些好用的特性。但是随着我使用地越多就越不想使用它。上一个躺坑的是我需要通过mockito来mock这些Mapper来做单元测试。简直麻了因为它自动生成的方法太灵活了尤其是链式方法。