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


    1 问题背景

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

    2 解决方案

    2.1 使用数据库加密算法

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

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

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

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

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

    • 加密算法可自由选择

    • 开发维护比较简单方便

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

    3 一般web项目使用

    3.1 创建自定义Java类型

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

    1. @Alias("SecretField")
    2. public class SecretField {
    3. }
    4. 复制代码

    3.2 自定义类的转换处理器

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

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

    1. @MappedTypes(SecretField.class)
    2. public class SecretFieldTypeHandler extends BaseTypeHandler {
    3. private static final Logger log = LoggerFactory.getLogger(SecretFieldTypeHandler.class);
    4. @Override
    5. public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
    6. try {
    7. if (StringUtils.hasText(parameter)) {
    8. String encryptStr = Sm4Util.encryptData_ECB(parameter);
    9. ps.setString(i, encryptStr);
    10. }
    11. } catch (Exception e) {
    12. ps.setString(i, parameter);
    13. log.error("mybatis加密参数异常,i:{},parameter:{}", i, parameter);
    14. }
    15. }
    16. @Override
    17. public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
    18. String columnValue = rs.getString(columnName);
    19. try {
    20. if (StringUtils.hasText(columnValue)) {
    21. columnValue = Sm4Util.decryptData_ECB(columnValue);
    22. }
    23. } catch (Exception e) {
    24. log.error("mybatis解密参数异常,columnName:{}, columnValue:{}", columnName, columnValue);
    25. }
    26. return columnValue;
    27. }
    28. @Override
    29. public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    30. return null;
    31. }
    32. @Override
    33. public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    34. return null;
    35. }
    36. }
    37. 复制代码

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

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

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

    1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    2. <!DOCTYPE configuration PUBLIC "-//mybaties.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    3. <configuration>
    4. <settings>
    5. </settings>
    6. <typeAliases>
    7. <typeAlias type="com.banxian.mybatis.alias.SecretField" alias="SecretField"/>
    8. </typeAliases>
    9. <typeHandlers>
    10. <typeHandler handler="com.banxian.mybatis.typehandler.SecretFieldTypeHandler" />
    11. </typeHandlers>
    12. </configuration>
    13. 复制代码

    3.4 查询使用

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

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

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

    3.5 新增修改使用

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

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

    4. springboot项目使用

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

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

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

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

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

    4.2 mybatis-plus的使用

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

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

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

    1. @Data
    2. @TableName(autoResultMap = true)
    3. public class User implements Serializable {
    4. private static final long serialVersionUID = 4344848828462926573L;
    5. @TableId(value = "id", type = IdType.ASSIGN_ID)
    6. private Integer id;
    7. /**
    8. * 名称
    9. */
    10. private String userName;
    11. /**
    12. * 是否删除 1:是 0:否
    13. */
    14. @TableLogic
    15. private String deleted;
    16. /**
    17. * 是否有效 1:是 0:否
    18. */
    19. private String valid;
    20. /**
    21. * 创建时间
    22. */
    23. @TableField(value = "create_at", fill = FieldFill.INSERT)
    24. private LocalDateTime createAt;
    25. /**
    26. * 更新时间
    27. */
    28. @TableField(value = "update_at", fill = FieldFill.INSERT_UPDATE)
    29. private LocalDateTime updateAt;
    30. @TableField(value = "sfz", typeHandler = SecretFieldTypeHandler.class)
    31. private String sfz;
    32. }
  • 相关阅读:
    「北大社送书」学习Flutter编程 — 《从零基础到精通Flutter开发》
    java多线程新
    培养现货黄金投资的盈利能力
    Python股票量化投资课学习记录1
    星火大模型AI接口Spring中项目中使用【星火、AIGC】
    opencv 图像的缩放(放大,缩小),翻转与旋转
    电子商务盛行,怎么提高商店转换率?
    Linux常用命令记录
    查看linux开发板的CPU频率
    openGauss学习笔记-83 openGauss 数据库管理-内存优化表MOT管理-内存表特性-MOT使用内存和存储规划
  • 原文地址:https://blog.csdn.net/m0_71777195/article/details/126659421