zoukankan      html  css  js  c++  java
  • java实现MySQL数据加密存储---自定义注解+自定义mybatis拦截器

    思路  调用拦截器 实现加解密

    通过自定义加解密拦截器  判断是否是 加解密实体类 的字段   调用 加解密处理类 执行具体算法加解密

    自定义类注解 

    /**
     * 注解敏感信息类的注解
     */
    @Inherited
    @Target({ ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SensitiveData {
    }
    View Code

    自定义字段注解

    /**
     * 注解敏感信息类中敏感字段的注解
     */
    @Inherited
    @Target({ ElementType.FIELD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SensitiveField {
    }
    View Code

    实体类加上  自定义类注解    字段加上 自定义字段注解

    @SensitiveData
    @TableName(value ="vip_card")
    @Data
    public class VipCardVO implements Serializable {
        /**
         * 主键
         */
        @TableId(type = IdType.AUTO)
        private Integer id;
    
        /**
         * 卡号
         */
        @SensitiveField
        private String cardNo;
    
        /**
         * 用户名
         */
        @SensitiveField
        private String name;
    
        /**
         * 性别
         */
        private Integer gender;
    
        /**
         * 年龄
         */
        private Integer age;
    
        /**
         * 邮箱
         */
        private String email;
    
        /**
         * 身份证号
         */
    
        private String idNumber;
    
        /**
         * 地址
         */
    
        private String address;
    
        /**
         * 手机号
         */
    
        private String phoneNumber;
    
        /**
         * 创建时间
         */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="Asia/Shanghai")
        private Date createTime;
    
        /**
         * 更新时间
         */
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="Asia/Shanghai")
        private Date updateTime;
    }
    View Code

    加解密处理类

    @Component
    public class AEScrypto {
    
        private final static String password = "V********=";
    
        /**
         * 加密
         *
         * @param declaredFields paramsObject所声明的字段
         * @param paramsObject   mapper中paramsType的实例
         * @return T
         * @throws IllegalAccessException 字段不可访问异常
         */
        public static <T> T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException {
            for (Field field : declaredFields) {
                //取出所有被EncryptDecryptField注解的字段
                SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
                if (!Objects.isNull(sensitiveField)) {
                    field.setAccessible(true);
                    Object object = field.get(paramsObject);
                    //暂时只实现String类型的加密
                    if (object instanceof String) {
                        String value = (String) object;
                        //加密  这里我使用自定义的AES加密工具
                        field.set(paramsObject, AESUtil.encrypt(value,password));
                    }
                }
            }
            return paramsObject;
        }
        /**
         * 解密
         *
         * @param result resultType的实例
         * @return T
         * @throws IllegalAccessException 字段不可访问异常
         */
        public static <T> T decrypt(T result) throws IllegalAccessException {
            //取出resultType的类
            Class<?> resultClass = result.getClass();
            Field[] declaredFields = resultClass.getDeclaredFields();
            for (Field field : declaredFields) {
                //取出所有被EncryptDecryptField注解的字段
                SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
                if (!Objects.isNull(sensitiveField)) {
                    field.setAccessible(true);
                    Object object = field.get(result);
                    //只支持String的解密
                    if (object instanceof String) {
                        String value = (String) object;
                        //对注解的字段进行逐一解密
                        field.set(result, AESUtil.decrypt(value,password));
                    }
                }
            }
            return result;
        }
    }
    View Code

    加解密工具算法工具类

    public class AESUtil {
    
        private static final String KEY_ALGORITHM = "AES";
        private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//默认的加密算
    
        /**
         * AES 加密操作
         *
         * @param content
         * @param password
         * @return
         */
        public static String encrypt(String content, String password) {
            try {
                Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
    
                byte[] byteContent = content.getBytes("utf-8");
    
                cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password));// 初始化为加密模式的密码器
    
                byte[] result = cipher.doFinal(byteContent);// 加密
    
    
                String encode = Base64.getEncoder().encodeToString(result);
                //encode.
                return encode;//通过Base64转码返回
            } catch (Exception ex) {
                Logger.getLogger(AESUtil.class.getName()).log(Level.SEVERE, null, ex);
            }
    
            return null;
        }
    
        /**
         * AES 解密操作
         *
         * @param content
         * @param password
         * @return
         */
        public static String decrypt(String content, String password) {
    
            try {
                Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
    
                cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password));
    
                //执行操作
                byte[] result = cipher.doFinal(Base64.getDecoder().decode(content));
    
                return new String(result, "utf-8");
            } catch (Exception ex) {
    //            log.error(ex.getMessage(),ex);
            }
    
            return null;
        }
    }
    View Code

    加密拦截器 实现mybatis 拦截器 接口

    @Component
    @Intercepts({
            @Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
    })
    public class EncryptInterceptor implements Interceptor {
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            //@Signature 指定了 type= parameterHandler 后,这里的 invocation.getTarget() 便是parameterHandler 
            //若指定ResultSetHandler ,这里则能强转为ResultSetHandler
            ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
            // 获取参数对像,即 mapper 中 paramsType 的实例
            Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
            parameterField.setAccessible(true);
    
            //取出实例
            Object parameterObject = parameterField.get(parameterHandler);
            if (parameterObject != null) {
                Class<?> parameterObjectClass = parameterObject.getClass();
                //校验该实例的类是否被@SensitiveData所注解
                SensitiveData sensitiveData = AnnotationUtils.findAnnotation(parameterObjectClass, SensitiveData.class);
                if (Objects.nonNull(sensitiveData)) {
                    //取出当前当前类所有字段,传入加密方法
                    Field[] declaredFields = parameterObjectClass.getDeclaredFields();
                    AEScrypto.encrypt(declaredFields, parameterObject);
                }
    
            }
            return invocation.proceed();
        }
     
        /**
         * 切记配置,否则当前拦截器不会加入拦截器链
         */
        @Override
        public Object plugin(Object o) {
            return Plugin.wrap(o, this);
        }
     
        /**
         * 自定义配置写入,没有自定义配置的可以直接置空此方法
         */
        @Override
        public void setProperties(Properties properties) {
        }
    }
    View Code

    解密拦截器 实现mybatis 拦截器 接口

    @Component
    @Intercepts({
            @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
    })
    public class DecryptInterceptor implements Interceptor {
     
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            //取出查询的结果
            Object resultObject = invocation.proceed();
            if (Objects.isNull(resultObject)) {
                return null;
            }
            //基于selectList
            if (resultObject instanceof ArrayList) {
                ArrayList resultList = (ArrayList) resultObject;
                if (!CollectionUtils.isEmpty(resultList) && needToDecrypt(resultList.get(0))) {
                    for (Object result : resultList) {
                        //逐一解密
                        AEScrypto.decrypt(result);
                    }
                }
            //基于selectOne
            } else {
                if (needToDecrypt(resultObject)) {
                    AEScrypto.decrypt(resultObject);
                }
            }
            return resultObject;
        }
     
        private boolean needToDecrypt(Object object) {
            Class<?> objectClass = object.getClass();
            SensitiveData sensitiveData = AnnotationUtils.findAnnotation(objectClass, SensitiveData.class);
            return Objects.nonNull(sensitiveData);
        }
     
     
        @Override
        public Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }
     
        @Override
        public void setProperties(Properties properties) {
     
        }
    }
    View Code
    古人学问无遗力,少壮工夫老始成。 纸上得来终觉浅,绝知此事要躬行。
  • 相关阅读:
    loaded the "*****" nib but the view outlet was not set 错误的解决办法。
    IBOutlet和IBAction
    initWithNibName 和 loadNibNamed 的区别
    iOS 应用是如何创建的
    Objective C中NULL、Nil、nil、NSNull 的区别
    Objective C数组的内存管理
    XCode 调试1
    META httpequiv 大全
    基于GoogleMap,Mapabc,51ditu,VirtualEarth,YahooMap Api接口的Jquery插件的通用实现(含源代码下载) 转
    SELECT 語法中,如何動態組合查詢條件(转)
  • 原文地址:https://www.cnblogs.com/wf-zhang/p/14939638.html
Copyright © 2011-2022 走看看