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

通过mybatis自定义参数类型转换器,进行数据库字段加密脱敏

1 问题背景

在数据库存储人员的信息时,有一些信息是敏感数据,如身份证号、出生地等。为了防止信息泄漏,这些信息不允许直接在数据库中查看,此时就需要对这些字段进行加密存储,但在页面查看的仍旧是解密后的数据。这里就涉及到加解密的问题,有两种解决方案。

2 解决方案

2.1 使用数据库加密算法

通过数据库自带的加密算法,在sql里直接使用算法加解密,这种有较多缺点,不推荐使用。

  • 写法繁琐,不易开发维护

  • 适配多种数据库时,算法难以统一,工作量也剧增

2.2 使用mybatis的自定义参数类型转换器

    通过自定义Java类型和类型转换器,并在mapper.xml里标注类型,通过mybatis进行加解密。

  • 加密算法可自由选择

  • 开发维护比较简单方便

  • 不存在适配多种数据库的问题

3 一般web项目使用

3.1 创建自定义Java类型

创建一个空白类,在mapper.xml文件查询和新增修改时标注说明,表示需要mybatis进行相关类型转换。

@Alias("SecretField")
public class SecretField {
}
复制代码

3.2 自定义类的转换处理器

这里使用国密SM4进行加解密,当然算法可自由选择别的如AES等。

@MappedTypes注解映射刚才的自定义Java类

@MappedTypes(SecretField.class)
public class SecretFieldTypeHandler extends BaseTypeHandler<String> {

    private static final Logger log = LoggerFactory.getLogger(SecretFieldTypeHandler.class);

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        try {
            if (StringUtils.hasText(parameter)) {
                String encryptStr = Sm4Util.encryptData_ECB(parameter);
                ps.setString(i, encryptStr);
            }
        } catch (Exception e) {
            ps.setString(i, parameter);
            log.error("mybatis加密参数异常,i:{},parameter:{}", i, parameter);
        }
    }

    @Override
    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String columnValue = rs.getString(columnName);
        try {
            if (StringUtils.hasText(columnValue)) {
                columnValue = Sm4Util.decryptData_ECB(columnValue);
            }
        } catch (Exception e) {
            log.error("mybatis解密参数异常,columnName:{}, columnValue:{}", columnName, columnValue);
        }
        return columnValue;
    }

    @Override
    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return null;
    }

    @Override
    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }
}
复制代码

3.3 配置自定义类型和类型转换器

这一步也可使用相关注解完成。

配置文件为mybatis的配置文件,如mybatis-config.xml。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE configuration PUBLIC "-//mybaties.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
    </settings>

    <typeAliases>
            <typeAlias type="com.banxian.mybatis.alias.SecretField" alias="SecretField"/>
    </typeAliases>
    <typeHandlers>
        <typeHandler handler="com.banxian.mybatis.typehandler.SecretFieldTypeHandler" />
    </typeHandlers>

</configuration>
复制代码

3.4 查询使用

查询返回需通过resultMap映射,在加密字段进行javaType指明需要的类型转换器

另外如果旧代码中结果集大量直接使用map返回,时间紧张的情况下,则可考虑写一个工具类,在service里调用进行手动解密,没得办法呀!。

    <resultMap id="BaseResultMap" type="User">
        <result column="sfz" property="sfz"  javaType="SecretField"/>
    </resultMap>
复制代码

3.5 新增修改使用

在设置相关参数值时,也就是在#{}里,使用javaType指明需要的类型转换器

   insert into ... values(...
    <if test="sfz!= null">
        #{sfz,jdbcType=VARCHAR,javaType=SecretField},
    </if>
   )
复制代码

4. springboot项目使用

  • 自定义类型和类型转换器代码和上面一样,这里不在赘述。

  • 项目使用了mybatis-plus插件。

4.1 配置自定义类型和类型转换器

在项目配置文件里application.yml里加上配置type-handlers-package 和   type-aliases-package:分别指出你的类型转换器所在包名和自定义类所在包名。

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted
      logic-not-delete-value: "0"
      logic-delete-value: "1"
  mapper-locations: "classpath*:/mapper/**/*.xml"
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  type-handlers-package: com.banxian.mybatis.typehandler
  type-aliases-package: com.banxian.mybatis.alias
复制代码

4.2 mybatis-plus的使用

当然上面web项目的查询、新增和修改使用方法这里也是可以正常使用的

1)在实体类上使用注解 @TableName(autoResultMap = true)

2)在加密字段上指明类型@TableField(value = "sfz", typeHandler = SecretFieldTypeHandler.class)

@Data
@TableName(autoResultMap = true)
public class User implements Serializable {

    private static final long serialVersionUID = 4344848828462926573L;

    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Integer id;

    /**
     * 名称
     */
    private String userName;

    /**
     * 是否删除 1:是  0:否
     */
    @TableLogic
    private String deleted;

    /**
     * 是否有效 1:是  0:否
     */
    private String valid;

    /**
     * 创建时间
     */
    @TableField(value = "create_at", fill = FieldFill.INSERT)
    private LocalDateTime createAt;

    /**
     * 更新时间
     */
    @TableField(value = "update_at", fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateAt;

    @TableField(value = "sfz", typeHandler = SecretFieldTypeHandler.class)
    private String sfz;
}

相关文章:

  • Win10修复IPv6优先访问
  • 盘点市面上七款好用的代码加密混淆工具,你都用过哪款?
  • STC15单片机-按键检测单击或长按(外部中断)
  • 卷积神经网络工作原理图,图卷积神经网络原理
  • 猿创征文 |【C++】C向C++知识的过度(下)
  • 期货行业首批信创试点单位转型实践|信创专题
  • Ambari升级Atlas1.1.0到2.2.0
  • 公众号搜题平台系统
  • 【PTHREAD】线程退出与取消
  • 组件命名报错 “Component name “XXX“ should always be multi-word”的解决方法
  • 离职前一定要删除这几个文件,不然你的微信聊天记录全被别人看了
  • Vue(模板语法1)
  • 银行利率bp是什么意思,bp是什么意思贷款利率
  • 暗月项目四
  • 目标检测——关键点检测学习记录(三):人体骨骼点检测——自底向上
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • AHK 中 = 和 == 等比较运算符的用法
  • Angular 4.x 动态创建组件
  • C++类中的特殊成员函数
  • CentOS 7 防火墙操作
  • es6--symbol
  • Flex布局到底解决了什么问题
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • Invalidate和postInvalidate的区别
  • LeetCode29.两数相除 JavaScript
  • MQ框架的比较
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Python_网络编程
  • python学习笔记 - ThreadLocal
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • SOFAMosn配置模型
  • Vue 动态创建 component
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 开源SQL-on-Hadoop系统一览
  • 目录与文件属性:编写ls
  • 前端性能优化--懒加载和预加载
  • 使用API自动生成工具优化前端工作流
  • 手写一个CommonJS打包工具(一)
  • 学习笔记TF060:图像语音结合,看图说话
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 鱼骨图 - 如何绘制?
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • 智能合约Solidity教程-事件和日志(一)
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • #includecmath
  • (06)金属布线——为半导体注入生命的连接
  • (2)MFC+openGL单文档框架glFrame
  • (LeetCode) T14. Longest Common Prefix
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (ZT)出版业改革:该死的死,该生的生
  • (附源码)ssm基于微信小程序的疫苗管理系统 毕业设计 092354
  • (力扣)循环队列的实现与详解(C语言)
  • (转)linux自定义开机启动服务和chkconfig使用方法