数据脱敏 注解模式

前言

基本各自项目的需求,数据保密性,以及数据安全问题,这时候又需要考虑客户的使用,那么数据的脱敏就显的尤为重要了。


一、基于注解的脱敏策略思路?

  1. 自定义注解接口
    自定义注解(示例说明):@DataTransForm(excute = true, stargy = IdCardStargy.class) 用于绑定脱敏属性的依据(且自定义设置脱敏策略类,是否脱敏)
  2. 编写脱敏策略类
    策略类(示例说明): IdCardStargy 实际的脱敏规则
  3. 脱敏工具类
    脱敏工具类 (示例说明):Utils 用于项目服务层对接口数据处理
  4. 脱敏策略管理类
    脱敏策略管理类(示例说明):Manager层利用反射解析对象Fileds,并获取有@DataTransForm注解的属性, 从策略类静态Map容器(项目启动时init维护)中获取对接的策略类,再利用策略调度器Handle去执行对应的实际策略类IdCardStargy,反射filed.set()方法实现脱敏!
  5. 控制层使用
    控制层实际使用示例。

二、代码展示

1.自定义注解

1.1 定义自定义注解两个属性1. excute() 2. stargy() 策略类(代码上有注释就不在一一赘述)

/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/12 17:05
 * @Version 1.0
 * @description: 脱敏需求处理自定义接口
 */
// 作用运行环境
@Retention(RetentionPolicy.RUNTIME)
// 作用的目标属性TYPE
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface DataTransForm {

    /**
     * 是否脱敏 默认true
     */
    boolean excute() default true;
    /**
     * 脱敏策略类
     * @return
     */
    Class<? extends TransformStargy> stargy();
}

2.脱敏策略类

2.1 脱敏策略类需要统一实现TransformStargy,实现统一方法transFrom(T args)

/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/12 17:23
 * @Version 1.0
 * @description: 策略类统一实现接口
 */
public interface TransformStargy<T> {

    /**
     * 加强实现 -- 实际脱敏规则
     * @param args 脱敏参数
     * @return
     */
     T transFrom(T args);
}

2.2 对应的具体身份证属性的脱敏规则类

/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 11:29
 * @Version 1.0
 * @description: 身份证脱敏类
 */
@Component
public class IdCardStargy implements TransformStargy<String> {


    //todo 实际身份证脱敏规则
    public String transFrom(String args) {
        return trans(args);
    }

    public static String trans(String args){
        char[] chars = args.toCharArray();
        if (chars.length > start + end) {
            for (int i = start; i < chars.length - end; i++) {
                chars[i] = symbol;
            }
        }
        return new String(chars);
    }
}

3.脱敏工具类

3.1 对应实际业务层直接采用工具类调用处理结果集合

/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 11:12
 * @Version 1.0
 * @description: 脱敏工具类 - return Object
 */
@Component
public class TransFormUtils {

    @Autowired
    TransFromManager transFromManager;

    public <T> void Desensitization(T t) {
        try {
            transFromManager.transformType(t);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    public <T> void DesensitizationList(List<T> tt) {
        try {
            for (Object object : tt) {
               transFromManager.transformType(object);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

4. 脱敏策略管理类

本次脱敏实现的两大核心内容为【策略类Map】和【调度器Handle】
4.1 策略类Map

4.1.1 脱敏策略类静态ContainerMap
4.1.2 项目启动时初始化ContainerMap,为后期可以根据key获取对应策略类做准备(需要注意:各个策略类都需要注入spring容器,否则无法维护ContainerMap init)。
/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 11:37
 * @Version 1.0
 * @description: 脱敏策略类map
 */
public class ContainerMap {
    private final HashMap<String, TransformStargy> container = new HashMap();
    private static ContainerMap instance = new ContainerMap();
    private ContainerMap(){}

    public static ContainerMap getInstance(){
        return instance;
    }
    /**
     * 添加策略类
     */
    public ContainerMap addStargy(TransformStargy stargy){
        Objects.requireNonNull(stargy, "不允许往策略容器中添加空策略");
        String key = stargy.getClass().getSimpleName();
        TransformStargy put = container.put(key, stargy);
        if(null != put){
            throw new RuntimeException("添加策略类重复");
        }
        return this;
    }
    /**
     * 获取策略类
     */
    public TransformStargy getStargy(Class<? extends TransformStargy> cls){
        Objects.requireNonNull(cls, "获取策略类key值为空");
        return container.get(cls.getSimpleName());
    }
}

/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 11:15
 * @Version 1.0
 * @description: 启动类 维护策略集合
 */
@Configuration
public class TransFormApplication implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    /**
     * 启动时候维护 策略类
     */
    @Bean
    public ContainerMap containerMap() {
        Map<String, TransformStargy> beansOfType = applicationContext.getBeansOfType(TransformStargy.class);
        ContainerMap instance = ContainerMap.getInstance();
        if (null != beansOfType && beansOfType.size() > 0) {
            for (String key : beansOfType.keySet()) {
                //todo 添加到容器
                instance.addStargy(beansOfType.get(key));
            }
        }
        return instance;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

4.2 调度器Handle

4.2.1 策略类的执行调用封装成了handle。(也可以直接用对应策略类调用策略实现方法)
/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 11:07
 * @Version 1.0
 * @description: 脱敏策略调度类
 */

public interface TransformHandle {
    <T> Object excute(T source, TransformStargy stargy);
}
/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 11:09
 * @Version 1.0
 * @description: 策略调度实现
 */
public class TransformHandleImpl implements TransformHandle {

    public <T> Object excute(T source, TransformStargy stargy) {
        return stargy.transFrom(source);
    }
}
4.2.2 配置类:组装了Map和handle。(也可以直接用对应实现类调用方法)
 /**
* @program: Data-Transform
* @Author wang dong
* @Date 2021/4/13 14:51
* @Version 1.0
* @description: 脱敏配置类  - 提供装配类
*/
@Configuration
public class TransformConfiguration {

 private ContainerMap containerMap;
 @Autowired
 TransformHandleImpl transformHandle;

 public TransformConfiguration(ContainerMap containerMap){
     this.containerMap = containerMap;
 }

 @Bean
 public TransFromManager transFromManager(){
     return  new TransFormManagerImpl(containerMap, handle());
 }

 @Bean
 public TransformHandle handle(){
     return new TransformHandleImpl();
 }
}

4.3 策略类Manager

4.3.1 脱敏策略管理接口
4.3.2 脱敏策略管理实现类: 
   4.3.2.1  通过反射获取属性集合遍历
   4.3.2.1  找到带有注解标记的属性,拿到注解信息 
   4.3.2.1  通过注解信息里面的策略类class找到Map中的策略类实体对象
   4.3.2.1  通过通过调度器Handle调度到对应的策略实现类,实现脱敏。
 /**
* @program: Data-Transform
* @Author wang dong
* @Date 2021/4/13 13:56
* @Version 1.0
* @description: 脱敏策略管理
*/
public interface TransFromManager {

 Object transformType(Object object) throws IllegalAccessException;
}
/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 14:07
 * @Version 1.0
 * @description: 脱敏策略类实现类
 */
@Service
public class TransFormManagerImpl implements TransFromManager {

    private ContainerMap containerMap;
    private TransformHandle transformHandle;

    public TransFormManagerImpl(ContainerMap containerMap, TransformHandle transformHandle) {
        Objects.requireNonNull(containerMap, "策略容器不能为空");
        Objects.requireNonNull(transformHandle, "调度器不能为空");
        this.containerMap = containerMap;
        this.transformHandle = transformHandle;
    }

    @Override
    public Object transformType(Object object) throws IllegalAccessException {
        Objects.requireNonNull(object, "muset be not null!");
        //此处拿到对象,应该遍历对象所有变量的注解,并使用注解名称获取Map中对应的策略进行数据转换
        List<Field> allField = ReflectUtil.getFieldByCurrentAndSuper(object.getClass());
        if (null != allField && allField.size() > 0) {
            for (int i = 0; i < allField.size(); i++) {
                Field field = allField.get(i);
                // 设置可访问私有属性
                field.setAccessible(true);
                if (field.getType() != null && field.getType().getClass().getClassLoader() != null) {
                    Object o = field.get(object);
                    if (o != null) {
                        transformType(o);
                    }
                }

                DataTransForm mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(field, DataTransForm.class);
                if (null == mergedAnnotation || (mergedAnnotation != null && !mergedAnnotation.excute())) {
                    continue;
                }
// 
                TransformStargy stargy = containerMap.getStargy(mergedAnnotation.stargy());
//                Object excute = stargy.transFrom(field.get(object));
                Object excute = transformHandle.excute(field.get(object), stargy);
                // todo 脱敏通过反射的替换
                field.set(object, excute);
            }
        }

        return object;
    }
}

5.使用

  • 控制层编写接口,调用测试, 亲测有效,附上结果
/**
* @program: Data-Transform
* @Author wang dong
* @Date 2021/4/13 20:04
* @Version 1.0
* @description: 控制
*/
@RestController
public class TrnasformController {
   @Autowired
   TransFormUtils transFormUtils;

   @GetMapping("/test")
   public Student getStudent(){
       Student student = new Student()
               .setAge(11)
               .setHigh("176cm")
               .setName("司藤")
               .setSex(1)
               .setIdCard("612324199312226732");
       System.out.println(student);
       transFormUtils.Desensitization(student);
       System.out.println("脱敏后数据:" + student);
       return student;
   }
}
  • 实体对象只需要添加注解,以及策略实现类。
/**
* @program: Data-Transform
* @Author wang dong
* @Date 2021/4/12 17:53
* @Version 1.0
* @description: 测试对象
*/

@Data
@Accessors(chain = true)
public class Student {

   public Integer age;

   @DataTransForm(excute = true, stargy = NameStargy.class)
   public String name;

   @DataTransForm(excute = true, stargy = IdCardStargy.class)
   public String idCard;

   public String high;

   public Integer sex;

}
  • 结果

在这里插入图片描述

在这里插入图片描述

总结

以上就是今天要讲的内容,本文仅仅是就从代码实现层面讲解了脱敏需求的实现。适合于后期数据优化,优点是代码改动少,但是需要注意接收到该接口数据的地方,数据在操作时需要去敏处理否则会报错哦。
  • 附件
/**
 * @program: Data-Transform
 * @Author wang dong
 * @Date 2021/4/13 20:04
 * @Version 1.0
 * @Description 反射工具类
 **/
public class ReflectUtil {

    /**
     * description: 从当前以及父类中获取全部字段
     * @param clazz 属性所在类
     * @return java.lang.reflect.Field
     */
    public static List<Field> getFieldByCurrentAndSuper(Class<?> clazz) {
        List<Field> fields = new ArrayList<>();
        getFieldByCurrentAndSuper(clazz, fields);
        return fields;
    }


    /**
     * description: 从当前以及父类中获取全部字段
     * @param clazz 属性所在类
     * @return java.lang.reflect.Field
     */
    private static List<Field> getFieldByCurrentAndSuper(Class<?> clazz, List<Field> fields) {
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            fields.add(declaredField);
        }
        if (!clazz.equals(Object.class)) {
            return getFieldByCurrentAndSuper(clazz.getSuperclass(), fields);
        }
        return fields;
    }
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值