问题
在项目中需要对用户敏感数据进行脱敏处理,例如身份号、手机号等信息进行加密再入库。
解决思路
-
就是:一种最简单直接的方式,在所有涉及数据敏感的查询到对插入时进行密码加解密
-
方法二:有方法一到出现对所有重大问题的影响,需要考虑到问题的出现,并且需要考虑可能出现的组员时添加数据的方法。
最后决定采用mybatis的插件在mybatis的SQL执行和结果填充操作上进行切入。上层业务调用不再需要考虑数据的加敏同时也保证了数据的加解密
Mybatis 插件原理
Mybatis 的是通过拦截器实现的,Mabatis 支持对当事人进行拦截
实现
-
设置对参数中带有敏感参数字段的数据时进行加密
-
对返回的结果进行解密处理
根据不同的要求,我们只需要对ParameterHandler和ResultSetHandler进行切入。定义特定注解,在切入时需要检查字段中是否包含注解来是否加解密。
加注解
定义SensitiveData注解
import java.lang.annotation.*; /** * 该注解定义在类上 * 插件通过扫描类对象是否包含这个注解来决定是否继续扫描其中的字段注解 * 这个注解要配合EncryptTransaction注解 **/ @Inherited @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface SensitiveData { }
定义EncryptTransaction注解
import java.lang.annotation.*; /** * 该注解有两种使用方式 * ①:配合@SensitiveData加在类中的字段上 * ②:直接在Mapper中的方法参数上使用 **/ @Documented @Inherited @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface EncryptTransaction { }
加解密工具类
解密
package sicnu.cs.ich.common.interceptor.transaction.service; public interface IDecryptUtil { /** * 解密 * * @param result resultType的实例 * @return T * @throws IllegalAccessException 字段不可访问异常 */ <T> T decrypt(T result) throws IllegalAccessException; }
加密接口
package sicnu.cs.ich.common.interceptor.transaction.service; import java.lang.reflect.Field; public interface IEncryptUtil { /** * 加密 * * @param declaredFields 加密字段 * @param paramsObject 对象 * @param <T> 入参类型 * @return 返回加密 * @throws IllegalAccessException 不可访问 */ <T> T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException; } package sicnu.cs.ich.common.interceptor.transaction.service.impl; import org.springframework.stereotype.Component; import sicnu.cs.ich.api.common.annotations.transaction.EncryptTransaction; import sicnu.cs.ich.common.interceptor.transaction.service.IDecryptUtil; import sicnu.cs.ich.common.util.keyCryptor.DBAESUtil; import java.lang.reflect.Field; import java.util.Objects; @Component public class DecryptImpl implements IDecryptUtil { /** * 解密 * * @param result resultType的实例 */ @Override public <T> T decrypt(T result) throws IllegalAccessException { //取出resultType的类 Class<?> resultClass = result.getClass(); Field[] declaredFields = resultClass.getDeclaredFields(); for (Field field : declaredFields) { //取出所有被DecryptTransaction注解的字段 EncryptTransaction encryptTransaction = field.getAnnotation(EncryptTransaction.class); if (!Objects.isNull(encryptTransaction)) { field.setAccessible(true); Object object = field.get(result); //String的解密 if (object instanceof String) { String value = (Strin