mybatis-data-security实现数据库数据加解密

Posted justry_deng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis-data-security实现数据库数据加解密相关的知识,希望对你有一定的参考价值。

Gitee地址 https://gitee.com/JustryDeng/mybatis-data-security


mybatis-data-security

介绍

  mybatis-data-security提供了一种基于注解实现数据库数据加解密的功能支持。

原理

  编写mybatis interceptor实现,对业务代码无侵入,在入库前加密,出库前解密。

前置条件

  • 项目采用mybatis作为持久层框架

功能特性

  • 项目启动时分析并校验加解密信息,若使用不当则快速失败
  • 支持直接对String类型的变量进行加解密(示例见下述步骤4)
  • 支持对POJO中String类型的字段进行加解密(示例见下述步骤4)
  • 支持自定义加解密实现

注意事项

  目前而言,加密后的密文/解密后的明文都会回写给原来的对象;但是有的时候,我们不希望加解密直接操作原来的对象,而是希望加解密时操作原对象的clone对象时,
就可以通过实现com.ideaaedi.mybatis.data.security.support.PojoCloneable接口来达到这个目的。

一般的,在下述场景下比较需要这种能力:

  • 入库加密时,加密后的密文不要回写到原来的对象中 —— 因为在某些业务场景下,入库后,后面的程序逻辑还需要取对应的明文值而不是密文值。
  • 出库解密时,解密后的明文不要回写到原来的对象中 —— 因为在某些业务场景下,出库后,后面的一些程序逻辑需要修改查询出来的对象的属性值, 你这里修改后;当别人使用相同的sql查询时,因为某些缓存机制的存在,就可能导致别人查出来的对象就是你现在在操作着的对象,随意这个对象 的值比起数据库数据来说,是"失真"了的

使用说明

  1. 引入相关依赖
    <dependency>
      <groupId>com.idea-aedi</groupId>
      <artifactId>mybatis-data-security</artifactId>
      <version>${version}</version>
    </dependency>
    
  2. 使用注解com.ideaaedi.mybatis.data.security.annotation.EnableMybatisDataSecurity,启用mybatis-data-security功能
    @SpringBootApplication
    @EnableMybatisDataSecurity
    public class YourApplication {
         // ...
    }
    
  3. 实现com.ideaaedi.mybatis.data.security.support.EncryptExecutor,定制加解密逻辑
    import com.ideaaedi.mybatis.data.security.annotation.Encrypt;
    import com.ideaaedi.mybatis.data.security.support.EncryptExecutor;
    import com.ideaaedi.mybatis.data.security.util.AesUtil;
    import org.springframework.stereotype.Component;
    
    /**
     * 实现自己的加解密器 - 示例
     *
     * @author JustryDeng
     * @since 2021/2/11 19:08:05
     */
    @Component
    public class MyEncryptExecutor implements EncryptExecutor {
    
        
        @Override
        public String encryptParameter(String paramName, String paramValue, Encrypt annotation) {
            return AesUtil.encrypt(paramValue);
        }
        
        @Override
        public String encryptField(String fieldName, String fieldValue, Encrypt annotation, Object pojo) {
            return AesUtil.encrypt(fieldValue);
        }
        
        @Override
        public String decryptField(String fieldName, String fieldValue, Encrypt annotation, Object pojo) {
            return AesUtil.decrypt(fieldValue);
        }
    }
    
  4. 使用注解com.ideaaedi.mybatis.data.security.annotation.Encrypt控制要加解密的字段
  • 示例一:直接对String类型的变量加密
    • case 1:
      @Insert("INSERT INTO employee (`id`,`name`) VALUES(#{id}, #{name})");
      int insertThree(@Param("id")int id, @Param("name") @Encrypt String name);
      
    • case 2:
      @MapKey("id")
      @Select("SELECT `id`,`name`,`age`,`gender`,`motto`,`birthday`,`hobby` FROM `employee` WHERE name = #{name}");
      Map<Integer, Employee> selectMapByName(@Encrypt @Param("name") String name);
      
  • 示例二:对POJO中String类型的字段加解密
    • pojo示例:
      @Data
      @Builder
      @NoArgsConstructor
      @AllArgsConstructor
      public class Employee {
      
                  /** 用户id */
                  private Integer id;
              
                  /** 名字 */
                  @Encrypt
                  private String name;
              
                  /** 年龄 */
                  private Integer age;
              
                  /** 性别 */
                  private String gender;
              
                  /** 座右铭 */
                  @Encrypt
                  private String motto;
              
                  /** 生日 */
                  private String birthday;
              
                  /** 爱好 */
                  @Encrypt
                  private String hobby;
              
      }
      
    • case 1: 单POJO入参
      @Insert("INSERT INTO employee (`id`,`name`, `age`, `gender`, `motto`, `birthday`, `hobby`) VALUES(#{u.id},#{u.name},#{u.age},#{u.gender},#{u.motto},#{u.birthday},#{u.hobby})")
      @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "u.id")
      int insertOne(@Param("u") Employee employee);
      
    • case 2: 单POJO入参
      @Insert("INSERT INTO employee (`id`, `name`, `age`, `gender`, `motto`, `birthday`, `hobby`) VALUES(#{id},#{name},#{age},#{gender},#{motto},#{birthday},#{hobby})")
      @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
      int insertTwo(Employee employee);
      
    • case 3: POJO放在MAP中入参
      @Insert("INSERT INTO employee (`id`, `name`, `age`) VALUES(#{u.id},#{u.name},#{u.age})")
      int insertEight(Map<String, Employee> paramsMap);
      
    • case 4: POJO放在MAP中入参
      @Insert("INSERT INTO employee (`id`,`name`, `age`) VALUES(#{p.u.id},#{p.u.name},#{p.u.age})")
      int insertNine(@Param("p") Map<String, Employee> paramsMap);
      
    • case 5: POJO放在COLLECTION中入参
      @InsertProvider(type = AbcMapperProvider.class, method = "insertTenProvider")
      int insertTen(List<Employee> employeeList);
      
    • case 6: POJO放在COLLECTION中入参
      @InsertProvider(type = AbcMapperProvider.class, method = "insertElevenProvider")
      int insertEleven(@Param("list") List<Employee> employeeList);
      
    • case 7: POJO放在ARRAY中入参
      @InsertProvider(type = AbcMapperProvider.class, method = "insertTwelveProvider")
      Integer insertTwelve(@Param("myArray") Employee[] employeeArray);
      
    • case 8: 单POJO出参
      @Select("SELECT `id`,`name`,`age`,`gender`,`motto`,`birthday`,`hobby` FROM `employee` WHERE id = #{id}")
      Employee selectOneById(@Param("id") Integer id);
      
    • case 9: POJO放在COLLECTION中出参
      @Select("SELECT `id`,`name`,`age`,`gender`,`motto`,`birthday`,`hobby` FROM `employee` ")
      List<Employee> selectAll();
      
    • case 10: POJO放在ARRAY中出参
      @Select("SELECT `id`,`name`,`age`,`gender`,`motto`,`birthday`,`hobby` FROM `employee` ")
      Employee[] selectAllAsArray();
      
    • case 11: POJO放在MAP中出参
      @Select("SELECT `id`,`name`,`age`,`gender`,`motto`,`birthday`,`hobby` FROM `employee` WHERE name = #{name}")
      Map<Integer, Employee> selectMapByName(@Encrypt @Param("name") String name);
      
    • case 12: …
      // ...
      

以上是关于mybatis-data-security实现数据库数据加解密的主要内容,如果未能解决你的问题,请参考以下文章

干货 | 快速实现数据导入及简单DCS的实现

delphi 中如何实现对象之间的数据共享

实现双向数据绑定

vue的数据双向绑定是怎么实现的

对实现数据版本管理,数据快照的研究与实现

Java多数据源实现教程实现动态数据源多数据源切换方式