解锁新技能《Java基于注解的脱敏实现组件SDK》

这篇具有很好参考价值的文章主要介绍了解锁新技能《Java基于注解的脱敏实现组件SDK》。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

平时开发的过程中经常会遇到对一些敏感的字段进行脱敏处理,防止信息泄漏,如:邮箱、用户名、密码等;做为一个优秀的程序员我们不应该遇到这种问题时就做特殊处理,重复做相同的工作,所以我们应该写一个基础库SDK,解决重复的问题;

开源SDK组件
<dependency>
  <groupId>io.github.mingyang66</groupId>
  <artifactId>oceansky-sensitive</artifactId>
  <version>4.3.2</version>
</dependency>

新增JsonNullField注解,可将指定的字段值置为null,注解定义如下:
/**
 * @Description :  自定义注解,标注在属性上,字段属性值置为null
 * ---------------------------------------------
 * 生效规则:
 * 1.非int、double、float、byte、short、long、boolean、char八种基本数据类型字段才会生效;
 * 2.
 * ---------------------------------------------
 * @Author :  Emily
 * @CreateDate :  Created in 2023/7/14 5:22 下午
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonNullField {

}

一、定义注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonSensitive {
}

@JsonSensitive标注在类上,表示此类需要进行脱敏处理;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonSimField {
    /**
     * 脱敏类型,见枚举类型{@link SensitiveType}
     *
     * @return
     */
    SensitiveType value() default SensitiveType.DEFAULT;
}

@JsonSimField标注在类的String、Collection、String[]字段上,表示对这些字段值进行脱敏处理;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonFlexField {
    /**
     * 要隐藏的参数key名称
     *
     * @return
     */
    String[] fieldKeys() default {};

    /**
     * 要隐藏的参数值的key名称
     *
     * @return
     */
    String fieldValue();

    /**
     * 脱敏类型,见枚举类型{@link SensitiveType}
     *
     * @return
     */
    SensitiveType[] types() default {};
}

@JsonFlexField注解标注在复杂数据类型字段上,具体的使用方法会在后面举例说明;

二、实现对字段脱敏处理的核心实现类
public class DeSensitiveUtils {

    public static final Logger logger = LoggerFactory.getLogger(DeSensitiveUtils.class);

    /**
     * @param entity 实体类|普通对象
     * @return 对实体类进行脱敏,返回原来的实体类对象
     */
    public static <T> T acquire(final T entity) {
        try {
            if (JavaBeanUtils.isFinal(entity)) {
                return entity;
            }
            if (entity instanceof Collection) {
                for (Iterator it = ((Collection) entity).iterator(); it.hasNext(); ) {
                    acquire(it.next());
                }
            } else if (entity instanceof Map) {
                for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) entity).entrySet()) {
                    acquire(entry.getValue());
                }
            } else if (entity.getClass().isArray()) {
                if (!entity.getClass().getComponentType().isPrimitive()) {
                    for (Object v : (Object[]) entity) {
                        acquire(v);
                    }
                }
            } else if (entity instanceof BaseResponse) {
                acquire(((BaseResponse) entity).getData());
            } else if (entity.getClass().isAnnotationPresent(JsonSensitive.class)) {
                doSetField(entity);
            }
        } catch (IllegalAccessException exception) {
            logger.error(PrintExceptionInfo.printErrorInfo(exception));
        }
        return entity;
    }

    /**
     * @param entity 实体类对象
     * @throws IllegalAccessException 非法访问异常
     * @Description 对实体类entity的属性及父类的属性遍历并对符合条件的属性进行多语言翻译
     */
    protected static <T> void doSetField(final T entity) throws IllegalAccessException {
        Field[] fields = FieldUtils.getAllFields(entity.getClass());
        for (Field field : fields) {
            if (JavaBeanUtils.isModifierFinal(field)) {
                continue;
            }
            field.setAccessible(true);
            Object value = field.get(entity);
            if (Objects.isNull(value)) {
                continue;
            }
            if (value instanceof String) {
                doGetEntityStr(field, entity, value);
            } else if (value instanceof Collection) {
                doGetEntityColl(field, entity, value);
            } else if (value instanceof Map) {
                doGetEntityMap(field, entity, value);
            } else if (value.getClass().isArray()) {
                doGetEntityArray(field, entity, value);
            } else {
                acquire(value);
            }
        }
        doGetEntityFlex(entity);
    }

    /**
     * @param field  实体类属性对象
     * @param entity 实体类对象
     * @param value  属性值对象
     * @throws IllegalAccessException 抛出非法访问异常
     * @Description 对字符串进行多语言支持
     */
    protected static <T> void doGetEntityStr(final Field field, final T entity, final Object value) throws IllegalAccessException {
        if (field.isAnnotationPresent(JsonSimField.class)) {
            field.set(entity, DataMaskUtils.doGetProperty((String) value, field.getAnnotation(JsonSimField.class).value()));
        } else {
            acquire(value);
        }
    }

    /**
     * @param field  实体类属性对象
     * @param entity 实体类对象
     * @param value  属性值对象
     * @throws IllegalAccessException 抛出非法访问异常
     * @Description 对Collection集合中存储是字符串、实体对象进行多语言支持
     */
    protected static <T> void doGetEntityColl(final Field field, final T entity, final Object value) throws IllegalAccessException {
        Collection<Object> list = null;
        Collection collection = ((Collection) value);
        for (Iterator it = collection.iterator(); it.hasNext(); ) {
            Object v = it.next();
            if (Objects.isNull(v)) {
                continue;
            }
            if ((v instanceof String) && field.isAnnotationPresent(JsonSimField.class)) {
                list = (list == null) ? Lists.newArrayList() : list;
                list.add(DataMaskUtils.doGetProperty((String) v, field.getAnnotation(JsonSimField.class).value()));
            } else {
                acquire(v);
            }
        }
        if (Objects.nonNull(list)) {
            field.set(entity, list);
        }
    }

    /**
     * @param field  实体类属性对象
     * @param entity 实体类对象
     * @param value  属性值对象
     * @throws IllegalAccessException 抛出非法访问异常
     * @Description 对Map集合中存储是字符串、实体对象进行多语言支持
     */
    protected static <T> void doGetEntityMap(final Field field, final T entity, final Object value) throws IllegalAccessException {
        Map<Object, Object> dMap = ((Map<Object, Object>) value);
        for (Map.Entry<Object, Object> entry : dMap.entrySet()) {
            Object key = entry.getKey();
            Object v = entry.getValue();
            if (Objects.isNull(v)) {
                continue;
            }
            if ((v instanceof String) && field.isAnnotationPresent(JsonSimField.class)) {
                dMap.put(key, DataMaskUtils.doGetProperty((String) v, field.getAnnotation(JsonSimField.class).value()));
            } else {
                acquire(value);
            }
        }
    }

    /**
     * @param field  实体类属性对象
     * @param entity 实体类对象
     * @param value  属性值对象
     * @throws IllegalAccessException 抛出非法访问异常
     * @Description 对数组中存储是字符串、实体对象进行多语言支持
     */
    protected static <T> void doGetEntityArray(final Field field, final T entity, final Object value) throws IllegalAccessException {
        if (value.getClass().getComponentType().isPrimitive()) {
            return;
        }
        Object[] arrays = ((Object[]) value);
        for (int i = 0; i < arrays.length; i++) {
            Object v = arrays[i];
            if (Objects.isNull(v)) {
                continue;
            }
            if ((v instanceof String) && field.isAnnotationPresent(JsonSimField.class)) {
                arrays[i] = DataMaskUtils.doGetProperty((String) v, field.getAnnotation(JsonSimField.class).value());
            } else {
                acquire(value);
            }
        }
    }

    /**
     * @param entity 实体类对象
     * @throws IllegalAccessException 抛出非法访问异常
     */
    protected static <T> void doGetEntityFlex(final T entity) throws IllegalAccessException {
        Field[] fields = FieldUtils.getFieldsWithAnnotation(entity.getClass(), JsonFlexField.class);
        for (Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(entity);
            if (Objects.isNull(value)) {
                continue;
            }
            JsonFlexField jsonFlexField = field.getAnnotation(JsonFlexField.class);
            if (Objects.isNull(jsonFlexField.fieldValue())) {
                return;
            }
            Field flexField = FieldUtils.getField(entity.getClass(), jsonFlexField.fieldValue(), true);
            if (Objects.isNull(flexField)) {
                return;
            }
            Object flexValue = flexField.get(entity);
            if (Objects.isNull(flexValue) || !(flexValue instanceof String)) {
                return;
            }
            int index = Arrays.asList(jsonFlexField.fieldKeys()).indexOf((String) value);
            if (index < 0) {
                return;
            }
            SensitiveType type;
            if (index >= jsonFlexField.types().length) {
                type = SensitiveType.DEFAULT;
            } else {
                type = jsonFlexField.types()[index];
            }
            flexField.set(entity, DataMaskUtils.doGetProperty((String) flexValue, type));
        }
    }
}

三、基于注解的脱敏SDK使用案例
  • 对实体类中字段为字符串类型脱敏处理
@JsonSensitive
public class PubRequest {
    @JsonSimField(SensitiveType.USERNAME)
    public String username;
    @JsonSimField
    public String password;
    }
  • 对实体类中字段是List、Map<String,String>、String[]集合类型进行脱敏处理
@JsonSensitive
public class PubRequest {
    @JsonSimField
    public Map<String, String> work;
    @JsonSimField
    public List<String> jobList;
    @JsonSimField
    public String[] jobs;
}
  • 实体类中的字段是复杂数据类型脱敏处理
@JsonSensitive
public class JsonRequest extends Animal{
    @JsonFlexField(fieldKeys = {"email", "phone"}, fieldValue = "fieldValue", types = {SensitiveType.EMAIL, SensitiveType.PHONE})
    private String fieldKey;
    private String fieldValue;
}

复杂数据类型其实就是fieldKey可以指定多个不同的字段名,fieldValue是具体的字段值,如果fieldKey是email时fieldValue传递的就是邮箱,就按照types中指定脱敏策略为邮箱的策略脱敏;

  • 实体类中的属性字段是集合类型,集合中存放的是嵌套的实体类
    @JsonSensitive
    public static class Job {
        @JsonSimField(SensitiveType.DEFAULT)
        private String work;
        @JsonSimField(SensitiveType.EMAIL)
        private String email;
    }

嵌套实体类属性字段

    public Job job;
    public Map<String, Object> work;
    public List<PubResponse.Job> jobList;
    public PubResponse.Job[] jobs;

如果实体类中的集合中存放的是实体类,并且这个实体类标注了@JsonSensitive注解,则会对嵌套实体类中标注了@JsonSimField、@JsonFlexField注解的字段进行脱敏处理;同样如果最外层是集合、数组、key-value类型则也会对内部嵌套的实体类进行脱敏处理;

本文只对脱敏SDK做大概的阐述,如果你需要源码可以到个人GitHub上去拉;本文的示例是对当前实体类对象本身进行脱敏处理,返回的还是原来的对象本身,个人GitHub示例中还有一个返回是非当前对象的SDK工具类SensitiveUtils;

GitHub地址:https://github.com/mingyang66/spring-parent文章来源地址https://www.toymoban.com/news/detail-423188.html

到了这里,关于解锁新技能《Java基于注解的脱敏实现组件SDK》的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 解锁新技能《logback标记日志过滤器MarkerFilter》

    开源日志SDK(纯java版) 在logback-classic中存在一个全局过滤器TurboFilter,TurboFilter是与LoggerContext绑定,会在会在其它过滤器之前执行;MarkerFilter是TurboFilter的一个子类,其作用是标记日志是否记录入文件之中,可以指定标记的日志记录到文件中;也可以指定标记的日志拒绝记录到

    2024年02月15日
    浏览(31)
  • 解锁新技能RestTemplate设置全局、单个请求超时时间及支持https请求

    springboot请求第三方接口时会用到RestTemplate,其底层实现逻辑默认是通过SimpleClientHttpRequestFactory来实现,具体由socket连接来实现;可以替换其默认实现为HttpComponentsClientHttpRequestFactory。 一、自定义RestTemplate实例对象 二、RestTemplate自定义全局超时时间 三、RestTemplate设置单个请求

    2023年04月09日
    浏览(30)
  • Java实现数据脱敏的方法

    在Java中,可以使用各种技术来实现数据脱敏,下面将介绍几种常见的Java实现数据脱敏的方法。 字符串截取 字符串截取是一种简单的数据脱敏方法,它将敏感数据的一部分字符替换成“”号或其他字符。例如,将身份证号码的前6位和后4位替换成“”号,这样可以保护身份证

    2024年02月16日
    浏览(37)
  • Java 实现数据脱敏的详细讲解

    数据脱敏是一种数据保护技术,它通过对敏感数据进行修改或替换,使得数据无法被识别或关联到个人身份,从而保护个人隐私。在Java中,可以通过各种技术来实现数据脱敏,本文将详细讲解Java实现数据脱敏的方法和技术。 数据脱敏是一种保护个人隐私的技术,它通过对敏

    2024年02月07日
    浏览(25)
  • Java 实现数据脱敏的技术方案

    数据脱敏是保护个人隐私的一种重要手段,它通过对敏感信息进行处理,将敏感信息转换为不敏感的信息,以保护个人隐私不被泄漏。在Java中,数据脱敏也是一项非常重要的技术,本文将从数据脱敏的概念、Java中的数据脱敏原理、Java中的数据脱敏方法以及如何实现数据脱敏

    2024年02月08日
    浏览(44)
  • 8.4Java EE——基于注解的AOP实现

    元素 描述 @Aspect 配置切面 @Pointcut 配置切点 @Before 配置前置通知 @After 配置后置通知 @Around 配置环绕方式 @AfterReturning 配置返回通知 @AfterThrowing 配置异常通知 下面通过一个案例演示基于注解的AOP的实现,案例具体实现步骤如下。

    2024年02月15日
    浏览(29)
  • 解锁新技能《spring如何将属性配置文件中的属性绑定到实体类中》

    在springboot中将配置文件中的属性绑定到指定的实体类上可以通过自动化配置的方式实现,也可以通过手动方式从Environment环境变量中取出再赋值给实体类;但是在有些场景下自动化配置这种方案是行不通的,例如:ApplicationListener、ApplicationContextInitializer进行初始化调用时属性

    2024年02月16日
    浏览(42)
  • Java实现对手机号、身份证号、护照号脱敏

    背景: 我们在项目中经常会需要用到用户的敏感信息,比如手机号、身份证号、护照号; 当数据需要在页面上进行展示的时候就需要进行脱敏,将其中几位变为 *。 官方文档: https://www.hutool.cn/docs/#/core/工具类/信息脱敏工具-DesensitizedUtil Hutool依赖: 代码实现: 执行结果:

    2024年02月15日
    浏览(28)
  • 解锁新技能《Git本地访问GitHub出现WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!警告》

    今天本地git访问github仓库的时候出现如下异常: 问题原因是SSH会把每个曾经访问过的Git服务器的公钥记录在/Users/xx/.ssh/known_hosts文件中,当下次访问时会核对公钥,如果和上次的记录不同,SSH就会发出警告。 解决方法:直接删除/Users/xx/.ssh/known_hosts文件。 GitHub地址:https://

    2024年02月14日
    浏览(33)
  • JAVA学习-注解.基于注解的单元测试

            基于注解的单元测试是一种使用注解来简化和增强测试代码编写和执行的方法。在Java中,有多个基于注解的单元测试框架可供选择,包括JUnit、TestNG等。下面将对几个常见的基于注解的单元测试框架进行概述,并介绍它们的特点、使用方法以及与其他框架的比较。

    2024年04月28日
    浏览(25)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包