• Mybatis实现自定义TypeHandler对字段数据进行加解密


    业务场景

    业务上有一张用户信息表,某些字段比如电话号码,身份证号等等字段,数据落库需要加密,查询出来的时候是否需要解密由你自己决定,如果给前端传输过程中也是需要密文的话,那就让前端去解密。

    在网上看了些方法,发现有一个文章是让继承什么BaseTypeHandler,用了之后发现不好用,实现了这个接口之后,全局都生效了,也可能是我配置的不对。
    在这里插入图片描述

    原因

    这里我去简单翻了一下源码,可以看到当我自定义了StringTypeHandler后,源码中处理JdbcType.VARCHAR类型的handler变成了自定义的RayStringTypeHandler,因为没有细致去找,大致猜想为,加载handler的时候可能是按照JdbcType.VARCHAR来加载的,导致默认的StringTypeHandler被覆盖掉了,所以才会出现这样的情况。
    有兴趣的可以去研究一下org.apache.ibatis.builder包下的BaseBuilder类,以及com.baomidou.mybatisplus.extension.spring下的MybatisSqlSessionFactoryBean类。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    建议的实现方法

    我这边讲下我的实现方法,其实也就是实现自定义TypeHandler,用到的类如下:

    AESUtil.java(其中有读取环境变量的操作,记得在配置文件中加上对应配置)

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.context.EnvironmentAware;
    import org.springframework.core.env.Environment;
    import org.springframework.stereotype.Component;
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    import javax.crypto.Cipher;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.nio.charset.StandardCharsets;
    
    @Component
    @Slf4j
    public class AESUtil implements CommandLineRunner, EnvironmentAware {
    
        /**
         * 加密用的Key 可以用26个字母和数字组成
         * 此处使用AES-128-CBC加密模式,key需要为16位。
         */
        public static String S_KEY;
        public static String IV_PARAMETER;
        private Environment environment;
    
        /**
         * 加密
         *
         * @param sSrc
         * @return
         * @throws Exception
         */
        public static String encrypt(String sSrc) throws Exception {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] raw = S_KEY.getBytes();
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes());//使用CBC模式,需要一个向量iv,可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
            byte[] encrypted = cipher.doFinal(sSrc.getBytes(StandardCharsets.UTF_8));
            return new BASE64Encoder().encode(encrypted);//此处使用BASE64做转码。
        }
    
        /**
         * 解密
         *
         * @param sSrc
         * @return
         */
        public static String decrypt(String sSrc) {
            try {
                byte[] raw = S_KEY.getBytes(StandardCharsets.UTF_8);
                SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes());
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
                byte[] encrypted1 = new BASE64Decoder().decodeBuffer(sSrc);//先用base64解密
                byte[] original = cipher.doFinal(encrypted1);
                return new String(original, StandardCharsets.UTF_8);
            } catch (Exception ex) {
                return null;
            }
        }
    
    
        @Override
        public void run(String... args) {
            AESUtil.S_KEY = environment.getProperty("internal.aes.key");
            AESUtil.IV_PARAMETER = environment.getProperty("internal.aes.iv");
        }
    
        @Override
        public void setEnvironment(Environment env) {
            this.environment = env;
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    在这里插入图片描述

    AesTypeHandler.java(如果读取的时候不需要解密,就把三个getResult方法中的AESUtil.decrypt()去掉)

    import com.mec.core.utils.AESUtil;
    import lombok.SneakyThrows;
    import org.apache.ibatis.type.JdbcType;
    import org.apache.ibatis.type.TypeHandler;
    
    import java.sql.CallableStatement;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    
    public class AesTypeHandler implements TypeHandler {
    
    
        @SneakyThrows
        @Override
        public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) {
            ps.setString(i, AESUtil.encrypt(parameter));
        }
    
        @Override
        public String getResult(ResultSet rs, String columnName) throws SQLException {
            return AESUtil.decrypt(rs.getString(columnName));
        }
    
        @Override
        public String getResult(ResultSet rs, int columnIndex) throws SQLException {
            return AESUtil.decrypt(rs.getString(columnIndex));
        }
    
        @Override
        public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
            return AESUtil.decrypt(cs.getString(columnIndex));
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    FilingUserInfo.java(实体类,对应数据库的表字段模型)
    在这里插入图片描述

    可以看到数据落库的时候,都已经加密
    在这里插入图片描述

    查询的时候,数据已经解密
    在这里插入图片描述

  • 相关阅读:
    GitHub这5个骚操作,大部分人不知道
    [论文笔记] Open-sora 2、视频数据集介绍 MSR-VTT
    【vue设计与实现】非原始值的响应式方案 10-如何代理Set和Map
    IO流 -- 调研
    SpringBoot SpringBoot 开发实用篇 6 监控 6.7 自定义端点
    索尼 toio™ 应用创意开发征文|教育与游戏的完美融合:toio™核心Q宝引领数字学习新潮流
    基于Python实现的AStar求解八数码问题
    基础sql语句记录
    【实践篇】一次Paas化热部署实践分享 | 京东云技术团队
    简单个人网页设计作业 静态HTML个人主题网页作业 DW个人网站模板下载 大学生简单个人网页作品代码 个人网页制作 学生个人网页Dreamweaver设计作业
  • 原文地址:https://blog.csdn.net/weixin_44388689/article/details/126162266