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

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


mybatis-data-security

介绍

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

原理

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

前置条件
  • 项目采用mybatis作为持久层框架,支持mybatis-plus
功能特性
  • 项目启动时分析并校验加解密信息,若使用不当则快速失败
  • 支持直接对String类型的变量进行加解密
  • 支持对POJO中String类型的字段进行加解密
  • 支持自定义加解密实现
注意事项

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


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

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

    mybatis项目

    <dependency>
      <groupId>com.idea-aedi</groupId>
      <artifactId>mybatis-data-security</artifactId>
      <version>1.4.0</version>
    </dependency>
    

    mybatis-plus项目

    <dependency>
      <groupId>com.idea-aedi</groupId>
      <artifactId>mybatis-data-security</artifactId>
      <version>1.4.1-mp3.5.1</version>
    </dependency>
    

    注:适配时,是基于mybatis-plus3.5.1版本适配的,其它版本的mybatis-plus也可以用

    注:适配时,只适配了常用功能的加解密

  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: …
      // ...
      

^_^ 本文已经被收录进《程序员成长笔记》 ,笔者JustryDeng

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值