實(shí)體單字段入庫加密出庫解密

package com.csw.encryptiontechnology.utils.mapperRSA;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SensitiveField {

}


package com.csw.encryptiontechnology.utils.mapperRSA;


import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SensitiveEntity {

}


package com.csw.encryptiontechnology.utils.mapperRSA;

import java.lang.reflect.Field;

public interface Sm4Service {
    <T> T encrypt(Field[] declaredFields, T paramsObject) throws Exception;

    <T> T decrypt(T result) throws Exception;


}

package com.csw.encryptiontechnology.utils.mapperRSA;

import cn.hutool.core.util.ReflectUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class Sm4ServiceImpl implements Sm4Service {


    @Override
    public <T> T encrypt(Field[] declaredFields, T paramsObject) throws Exception {
        for (Field field : declaredFields) {
            //取出所有被EncryptDecryptField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (Objects.isNull(sensitiveField)) {
                continue;
            }
            field.setAccessible(true);
            Object object = field.get(paramsObject);
            //暫時(shí)只實(shí)現(xiàn)String類型的加密
            if (object instanceof String) {
                String value = (String) object;
                //如果映射字段值為空,并且以==結(jié)尾則跳過不進(jìn)行加密
                if (StringUtils.isEmpty(value) || isBase64(value)) {
                    continue;
                }
                //加密  這里我使用自定義的AES加密工具
                field.set(paramsObject, Sm4Util.encrypt(value));
            }
        }
        return paramsObject;

    }

    @Override
    public <T> T decrypt(T result) throws Exception {
        //取出resultType的類
        Class<?> resultClass = result.getClass();
        Field[] allFields = ReflectUtil.getFields(resultClass);
        //Field[] declaredFields = resultClass.getDeclaredFields();
        for (Field field : allFields) {
            //取出所有被EncryptDecryptField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (Objects.isNull(sensitiveField)) {
                continue;
            }
            field.setAccessible(true);
            Object object = field.get(result);
            //只支持String的解密
            if (object instanceof String) {
                String value = (String) object;
                //如果映射字段值為空,并且不已==結(jié)尾則跳過不進(jìn)行解密/之前加密方式不一樣,所以注掉
                if (StringUtils.isBlank(value)/* || !EncryptUtil.isBase64(value)*/) {
                    continue;
                }
                //對(duì)注解的字段進(jìn)行逐一解密
                field.set(result, Sm4Util.decrypt(value));
            }
        }
        return result;
    }

    /**
     * base64驗(yàn)證規(guī)則
     */
    private static final String BASE64_RULE = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)=?$";

    /**
     * 正則驗(yàn)證對(duì)象
     */
    private static final Pattern PATTERN = Pattern.compile(BASE64_RULE);


    /**
     * 判斷是否為 base64加密
     *
     * @param str 參數(shù)
     * @return 結(jié)果
     */
    public static boolean isBase64(String str) {
        Matcher matcher = PATTERN.matcher(str);
        return matcher.matches();
    }

}



package com.csw.encryptiontechnology.utils.mapperRSA;


import cn.hutool.crypto.symmetric.SymmetricCrypto;
import org.bouncycastle.util.encoders.Hex;


public class Sm4Util {


    public static final String key = "0123456789abcdeffedcba9876543210";

    public static void main(String arg[]) throws Exception {

        String paramStr = "pass$123";

        String arfter = encrypt(paramStr);
        String brfore = decrypt(arfter);
        arfter = arfter.toLowerCase();
        System.out.println("明文:---------------------" + paramStr);
        System.out.println("加密后密文:---------------------" + arfter);
        System.out.println("解密后明文:---------------------" + brfore);

    }


    /**
     * 加密
     */

    public static String encrypt(String data) {
        byte[] sm4KeyBytes = Hex.decode(key);
        SymmetricCrypto sm4 = new SymmetricCrypto("SM4/ECB/PKCS5Padding", sm4KeyBytes);
        return sm4.encryptHex(data).toUpperCase();
    }


    /**
     * 解密
     */

    public static String decrypt(String data) {
        try {
            byte[] sm4KeyBytes = Hex.decode(key);
            SymmetricCrypto sm4 = new SymmetricCrypto("SM4/ECB/PKCS5Padding", sm4KeyBytes);
            return sm4.decryptStr(data);
        } catch (Exception e) {
            return data;
        }
    }
}

package com.rd.common.interceptor;

import cn.hutool.core.util.ReflectUtil;
import com.csw.encryptiontechnology.utils.mapperRSA.SensitiveEntity;
import com.csw.encryptiontechnology.utils.mapperRSA.Sm4Service;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Properties;

@Component
@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),
        @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@Slf4j
public class MyBatisInterceptor implements Interceptor {
    @Resource
    private Sm4Service sm4Service;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        //攔截sql結(jié)果處理器
        if (target instanceof ResultSetHandler) {
            return resultDecrypt(invocation);
        }
        //攔截sql參數(shù)處理器
        if (target instanceof ParameterHandler) {
            return parameterEncrypt(invocation);
        }
        //攔截sql語句處理器
        if (target instanceof StatementHandler) {
            return replaceSql(invocation);
        }
        return invocation.proceed();
    }

    /**
     * 對(duì)mybatis映射結(jié)果進(jìn)行字段解密
     *
     * @param invocation 參數(shù)
     * @return 結(jié)果
     * @throws Throwable 異常
     */
    private Object resultDecrypt(Invocation invocation) throws Throwable {
        //取出查詢的結(jié)果
        Object resultObject = invocation.proceed();
        if (Objects.isNull(resultObject)) {
            return null;
        }
        //基于selectList
        if (resultObject instanceof ArrayList) {
            ArrayList resultList = (ArrayList) resultObject;
            if (CollectionUtils.isEmpty(resultList)) {
                return resultObject;
            }
            for (Object result : resultList) {
                if (needToDecrypt(result)) {
                    //逐一解密
                    sm4Service.decrypt(result);
                }
            }
            //基于selectOne
        } else {
            if (needToDecrypt(resultObject)) {
                sm4Service.decrypt(resultObject);
            }
        }
        return resultObject;
    }

    /**
     * mybatis映射參數(shù)進(jìn)行加密
     *
     * @param invocation 參數(shù)
     * @return 結(jié)果
     * @throws Throwable 異常
     */
    private Object parameterEncrypt(Invocation invocation) throws Throwable {
        //@Signature 指定了 type= parameterHandler 后呐芥,這里的 invocation.getTarget() 便是parameterHandler
        //若指定ResultSetHandler 硫狞,這里則能強(qiáng)轉(zhuǎn)為ResultSetHandler
        ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
        // 獲取參數(shù)對(duì)像重抖,即 mapper 中 paramsType 的實(shí)例
        Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
        parameterField.setAccessible(true);
        //取出實(shí)例
        Object parameterObject = parameterField.get(parameterHandler);

        if (parameterHandler.getParameterObject() instanceof MapperMethod.ParamMap) {
            MapperMethod.ParamMap paramMap = (MapperMethod.ParamMap) parameterHandler.getParameterObject();
            try {
                boolean b = paramMap.containsKey("param1");
                if (b == true) {
                    parameterObject = paramMap.get("param1");
                } else {
                    b = paramMap.containsKey("et");
                    if (b) {
                        parameterObject = paramMap.get("et");
                    } else {
                        parameterObject = null;
                    }
                }

            } catch (Exception e) {
                parameterObject = null;
            }
        }
        if (null == parameterObject) {
            return invocation.proceed();
        }
        Class<?> parameterObjectClass = parameterObject.getClass();
        //校驗(yàn)該實(shí)例的類是否被@SensitiveEntity所注解
        SensitiveEntity sensitiveEntity = AnnotationUtils.findAnnotation(parameterObjectClass, SensitiveEntity.class);
        //未被@SensitiveEntity所注解 則為null
        if (Objects.isNull(sensitiveEntity)) {
            return invocation.proceed();
        }
        //取出當(dāng)前當(dāng)前類所有字段,傳入加密方法
        //Field[] declaredFields = parameterObjectClass.getDeclaredFields();
        Field[] allFields = ReflectUtil.getFields(parameterObjectClass);
        sm4Service.encrypt(allFields, parameterObject);
        return invocation.proceed();
    }

    /**
     * 替換mybatis Sql中的加密Key
     *
     * @param invocation 參數(shù)
     * @return 結(jié)果
     * @throws Throwable 異常
     */
    private Object replaceSql(Invocation invocation) throws Throwable {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        //獲取到原始sql語句
        String sql = boundSql.getSql();
        if (null == sql) {
            return invocation.proceed();
        }
        //通過反射修改sql語句
        Field field = boundSql.getClass().getDeclaredField("sql");
        field.setAccessible(true);
        field.set(boundSql, sql);
        return invocation.proceed();
    }

    /**
     * 判斷是否包含需要加解密對(duì)象
     *
     * @param object 參數(shù)
     * @return 結(jié)果
     */
    private boolean needToDecrypt(Object object) {
        if (Objects.isNull(object)) {
            return false;
        }
        Class<?> objectClass = object.getClass();
        //Class<?> parentClass = objectClass.getSuperclass();
        SensitiveEntity sensitiveEntity = AnnotationUtils.findAnnotation(objectClass, SensitiveEntity.class);
        //SensitiveEntity parentSensitiveEntity = AnnotationUtils.findAnnotation(parentClass, SensitiveEntity.class);

        return Objects.nonNull(sensitiveEntity);/*|| Objects.nonNull(parentSensitiveEntity);*/
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蛾茉,隨后出現(xiàn)的幾起案子权薯,更是在濱河造成了極大的恐慌姑躲,老刑警劉巖睡扬,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異黍析,居然都是意外死亡卖怜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門阐枣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來马靠,“玉大人,你說我怎么就攤上這事侮繁÷侵啵” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵宪哩,是天一觀的道長娩贷。 經(jīng)常有香客問我,道長锁孟,這世上最難降的妖魔是什么彬祖? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮品抽,結(jié)果婚禮上储笑,老公的妹妹穿的比我還像新娘。我一直安慰自己圆恤,他們只是感情好突倍,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盆昙,像睡著了一般羽历。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淡喜,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天秕磷,我揣著相機(jī)與錄音,去河邊找鬼炼团。 笑死澎嚣,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瘟芝。 我是一名探鬼主播易桃,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼锌俱!你這毒婦竟也來了颈抚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贩汉,沒想到半個(gè)月后驱富,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匹舞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年褐鸥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赐稽。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叫榕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出姊舵,到底是詐尸還是另有隱情晰绎,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布括丁,位于F島的核電站荞下,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏史飞。R本人自食惡果不足惜尖昏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望构资。 院中可真熱鬧抽诉,春花似錦、人聲如沸吐绵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽己单。三九已至唉窃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荷鼠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工榔幸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留允乐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓削咆,卻偏偏與公主長得像牍疏,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拨齐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容