当前位置: 代码网 > it编程>编程语言>Java > mybatis用拦截器实现字段加解密全过程

mybatis用拦截器实现字段加解密全过程

2025年08月08日 Java 我要评论
前言根据公司业务需要,灵活对客户敏感信息进行加解密,这里采用mybatis拦截器进行简单实现个demo。拦截器的使用// 执行executor (update, query, flushstateme

前言

根据公司业务需要,灵活对客户敏感信息进行加解密,这里采用mybatis拦截器进行简单实现个demo。

拦截器的使用

// 执行
executor (update, query, flushstatements, commit, rollback, gettransaction, close, isclosed)
// 请求参数处理
parameterhandler (getparameterobject, setparameters)
// 返回结果集处理
resultsethandler (handleresultsets, handleoutputparameters)
// sql语句构建
statementhandler (prepare, parameterize, batch, update, query)

我们要实现数据加密,进入数据库的字段不能是真实的数据,但是返回来的数据要真实可用,所以我们需要针对 parameter 和 resultset 两种类型处理,同时为了更灵活的使用,我们需要自定义注解。

/**
 *需要加解密的字段注解
**/
@target({elementtype.field})
@retention(retentionpolicy.runtime)
@documented
public @interface encryption {
    string encryptiontype() default "";
}

编写一下加解密算法(随便找的)

**
 * @desc: aes对称加密,对明文进行加密、解密处理
 * @author:
 * @createtime: 20231014 上午9:54:52
 * @version: v0.0.1
 */
public class aesutil {
    private static final string key_algorithm = "aes";
    private static final string cipher_algorithm = "aes/ecb/pkcs5padding";


    /**
     * @desc: aes对称-加密操作
     * @version: v0.0.1
     * @param keystr 进行了base64编码的秘钥
     * @param data 需要进行加密的原文
     * @return string 数据密文,加密后的数据,进行了base64的编码
     */
    public static string encrypt(string keystr, string data) throws exception {
        // 转换密钥
        key key = new secretkeyspec(base64.getdecoder().decode(keystr), key_algorithm);
        cipher cipher = cipher.getinstance(cipher_algorithm);
        // 加密
        cipher.init(cipher.encrypt_mode, key);
        byte[] result = cipher.dofinal(data.getbytes());
        return base64.getencoder().encodetostring(result);
    }
    /**
     * @desc: aes对称-解密操作
     * @version: v0.0.1
     * @param keystr 进行了base64编码的秘钥
     * @param data 需要解密的数据<span style="color:red;">(数据必须是通过aes进行加密后,对加密数据base64编码的数据)</span>
     * @return string 返回解密后的原文
     */
    public static string decrypt(string keystr, string data) throws exception {
        // 转换密钥
        key key = new secretkeyspec(base64.getdecoder().decode(keystr), key_algorithm);
        cipher cipher = cipher.getinstance(cipher_algorithm);
        // 解密
        cipher.init(cipher.decrypt_mode, key);
        byte[] result = cipher.dofinal(base64.getdecoder().decode(data));
        return new string(result);
    }


    /**
     * @desc: 生成aes的秘钥,秘钥进行了base64编码的字符串
     * @version: v0.0.1
     * @return string 对生成的秘钥进行了base64编码的字符串
     */
    public static string keygenerate() throws exception {
        // 生成密钥
        keygenerator keygenerator = keygenerator.getinstance(key_algorithm);
        keygenerator.init(new securerandom());
        secretkey secretkey = keygenerator.generatekey();
        byte[] keybytes = secretkey.getencoded();
        return base64.getencoder().encodetostring(keybytes);
    }
    public static void main(string[] args) throws exception {
        system.out.println(
                keygenerate()
        );

    }
}

编写一下加解密接口

/**
 * 加解密处理接口
 */
public interface cipherhandler {

    /**
     * 加密
     * @param data 需要加密的数据
     * @return 加密结果
     */
   string encrypt(string data) throws exception;

    /**
     * 解密
     * @param data 需要加密的数据
     * @return 解密结果
     */
    string decrypt(string data) throws exception;

}

public class aescipher implements cipherhandler{
    private final static string keystr="glrwfsbckzppyvqiwt8m/q==";

    @override
    public string encrypt(string data) throws exception {
        return aesutil.encrypt(this.keystr,data);
    }

    @override
    public string decrypt(string data) throws exception {
        return aesutil.decrypt(this.keystr,data);
    }

    public static cipherhandler getaescipher(){
        return new aescipher();
    }
}

接下来写一下加解密的拦截器

@intercepts({
        @signature(type = parameterhandler.class, method = "setparameters", args = preparedstatement.class),
})
@component
@slf4j
public class parameterinterceptor implements interceptor {

    private cipherhandler cipherhandler = aescipher.getaescipher();
    @override
    public object intercept(invocation invocation) throws throwable {
        defaultparameterhandler parameterhandler = (defaultparameterhandler) invocation.gettarget();
        // 获取参数对像,即 mapper 中 paramstype 的实例
        field parameterfield = parameterhandler.getclass().getdeclaredfield("parameterobject");
        parameterfield.setaccessible(true);
        // 取出实例
        object parameterobject = parameterfield.get(parameterhandler);
        try {
            // 搜索该方法中是否有需要加密的字段
            list<field> fieldlist = searchparamannotation(parameterhandler);
            //加密
            if(!commonhelper.isempty(fieldlist)){
                dealparamencrypt(fieldlist,parameterobject);
            }
            parameterfield.set(parameterhandler, parameterobject);
            preparedstatement ps = (preparedstatement) invocation.getargs()[0];
            parameterhandler.setparameters(ps);

        } catch (exception e) {
            log.info(e.getmessage());
        }
        return invocation.proceed();
    }


    /**
     * 查找需要需要加密字段
     * @param parameterhandler
     * @return
     * @throws exception
     */
    private list<field> searchparamannotation(parameterhandler parameterhandler) throws exception {
        class<defaultparameterhandler> handlerclass = defaultparameterhandler.class;
        field mappedstatementfiled = handlerclass.getdeclaredfield("mappedstatement");
        mappedstatementfiled.setaccessible(true);
        mappedstatement mappedstatement = (mappedstatement) mappedstatementfiled.get(parameterhandler);
        string methodname = mappedstatement.getid();
        // 获取mapper类对象
        class<?> mapperclass = class.forname(methodname.substring(0, methodname.lastindexof('.')));
        methodname = methodname.substring(methodname.lastindexof('.') + 1);
        method[] methods = mapperclass.getdeclaredmethods();
        method method = null;
        for (method m : methods) {
            if (m.getname().equals(methodname)) {
                method = m;
                break;
            }
        }
        list<field> fieldlist = new arraylist<>();
        if (method != null) {
            annotation[][] pa = method.getparameterannotations();
            parameter[] parameters = method.getparameters();
            for (int i = 0; i < pa.length; i++) {
                parameter parameter = parameters[i];
                string typename = parameter.getparameterizedtype().gettypename();
                // 去除泛型导致的classnotfoundexception
                class<?> parameterclass = class.forname(typename.contains("<") ? typename.substring(0, typename.indexof("<")) : typename);
                field[] declaredfields = parameterclass.getdeclaredfields();
                for (field declaredfield : declaredfields) {
                    annotation annotation = declaredfield.getannotation(encryption.class);
                    if(!commonhelper.isempty(annotation))fieldlist.add(declaredfield);
                }
            }
        }
        return fieldlist;
    }

    /**
     * 处理加密类
     * @param fields
     * @param parameterobject
     * @throws exception
     */
    private void dealparamencrypt(list<field> fields,object parameterobject) throws exception {
        fields.foreach(declaredfield->{
            declaredfield.setaccessible(true);
            object o = null;
            try {
                o = declaredfield.get(parameterobject);
                declaredfield.set(parameterobject,cipherhandler.encrypt(o.tostring()));
            } catch (exception e) {
                throw new runtimeexception(e);
            }
        });

    }

    @override
    public object plugin(object target) {
        return plugin.wrap(target,this);
    }

    @override
    public void setproperties(properties properties) {

    }

}

查询结果解密

@intercepts({
        @signature(type = resultsethandler.class, method = "handleresultsets", args = {statement.class})
})
@component
public class resultsetinterceptor implements interceptor {

    private cipherhandler cipherhandler = aescipher.getaescipher();
    @override
    public object intercept(invocation invocation) throws throwable {
        // 取出查询的结果
        object resultobject = invocation.proceed();
        if (objects.isnull(resultobject)) {
            return null;
        }
        // 基于selectlist
        if (resultobject instanceof list<?>) {
            list<?> resultlist = (list<?>) resultobject;
            if (!commonhelper.isempty(resultlist)) {
                for (object obj : resultlist) {
                    todecrypt(obj);
                }
            }
        } else {
            todecrypt(resultobject);
        }
        return resultobject;
    }

    private void todecrypt(object object) throws exception {
        class<?> objectclass = object.getclass();
        field[] declaredfields = objectclass.getdeclaredfields();
        for (field declaredfield : declaredfields) {
            annotation annotation = declaredfield.getannotation(encryption.class);
            if(!commonhelper.isempty(annotation)){
                declaredfield.setaccessible(true);
                declaredfield.set(object,cipherhandler.decrypt(declaredfield.get(object).tostring()));
            }
        }
    }

    @override
    public object plugin(object o) {
        return plugin.wrap(o,this);
    }

    @override
    public void setproperties(properties properties) {

    }
}

判空工具类

public class commonhelper {

    public static boolean isempty(object o){
        if(o==null)return true;
        if(o instanceof string){
          return  ((string) o).isempty();
        }else if(o instanceof list){
            return collectionutils.isempty((list) o) || ((list<?>) o).size()==0 ;
        }else if(o instanceof map){
            return collectionutils.isempty((map) o) || ((map<?,?>) o).size()==0 ;
        }else {
            return objects.isnull(o);
        }
    }
}

测试结果:

  • 插入数据

  • 查询数据:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com