栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

开发中对敏感字段进行脱敏方法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

开发中对敏感字段进行脱敏方法

注解实现数据脱敏操作

在项目中经常使用到数据脱敏,这里使用 fasterxml.jackson来实现返回数据的脱敏操作

在这里借助 com.fasterxml.jackson.databind.JsonSerializer接口来完成对数据序列化的时候的操作

*引入包文件*


    com.fasterxml.jackson.core
    jackson-core
    2.11.4


    com.fasterxml.jackson.core
    jackson-annotations
    2.11.4


    com.fasterxml.jackson.core
    jackson-databind
    2.11.4


    com.fasterxml.jackson.datatype
    jackson-datatype-jsr310
    2.13.0


    com.alibaba
    fastjson
    1.2.76

一、创建策略

在序列化的时候需要指定序列化的规则,例如

字段长度 大于 10 前三后四明文字段长度 小于 4 无明文字段长度 大其他 后四明文

这里使用工具类来实现这个通用的操作

public class SensitiveUtils {
    public static final String SYMBOL_STAR = "*";
    
    public static String commonSensitive(String sensitiveValue) {
        if (StringUtils.isBlank(sensitiveValue)) {
            return sensitiveValue;
        }
        if (sensitiveValue.length() > 10) {
            int s = sensitiveValue.length() - 7;
            return sensitiveValue.replaceAll("(\w{3})\w{" + s + "}(\w{4})", "$1" + getStars(s) + "$2");
        } else if (sensitiveValue.length() < 4) {
            return getStars(sensitiveValue.length());
        } else {
            int s = sensitiveValue.length() - 4;
            return sensitiveValue.replaceAll("\w{" + s + "}(\w{4})", getStars(s) + "$1");
        }
    }
    
    public static boolean simpleInvalidSensitive(String value) {
        if (StringUtils.isBlank(value)) {
            return false;
        }
        return value.contains(SYMBOL_STAR);
    }
    public static String getStars(int s) {
        String stars = StringUtils.EMPTY;
        for (int i = 0; i < s; i++) {
            stars += SYMBOL_STAR;
        }
        return stars;
    }
}

上面的是一个通用的工具类,下面,我们使用接口来实例化这个通用的策略:

首先是接口:

public interface MyStrategy {   
String desensitizationByPattern(String source);
}

//然后构建一个默认的策略:

public class MyDefaultStrategy implements MyStrategy {
    public String desensitizationByPattern(String source) {
        return SensitiveUtils.commonSensitive(source);
    }
}

这个操作就是传入一个字段返回脱敏后的字符串,到这里就完成了一个策略的制定

二、构建序列化注解

这个注解用来明确字段序列化时需要的序列化器和使用的策略,这里要用到注解 @JsonSerialize,它的参数 using用来明确使用的序列化器,这里使用自定义的序列化器,下一节介绍序列化器的创建。

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = MySensitiveInfoSerialize.class)
@Inherited
public @interface CommonSensitive {
    
    Class strategy() default MyDefaultStrategy.class;
}

从上面可以看出来,这里的参数是一个接口性质的序列化策略,也就是说,后面是支持自定义的。

三、创建序列化器

序列化器要实现接口 com.fasterxml.jackson.databind.JsonSerializer

并实现方法

@Slf4j
@NoArgsConstructor
public class MySensitiveInfoSerialize extends JsonSerializer implements
        ContextualSerializer {
    private MyStrategy myStrategy;
    public MySensitiveInfoSerialize(MyStrategy myStrategy) {
        this.myStrategy = myStrategy;
    }
    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(myStrategy.desensitizationByPattern(s));
    }
    @Override
    public JsonSerializer createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            // 非 String 类直接跳过
            if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
                CommonSensitive sensitiveInfo = beanProperty.getAnnotation(CommonSensitive.class);
                if (sensitiveInfo == null) {
                    sensitiveInfo = beanProperty.getContextAnnotation(CommonSensitive.class);
                }
                if (sensitiveInfo != null) {
                    Class clazz = sensitiveInfo.strategy();
                    // 如果能得到注解,就将注解的 value 传入 SensitiveInfoSerialize
                    try {
                        return new MySensitiveInfoSerialize(clazz.getDeclaredConstructor().newInstance());
                    } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
                             NoSuchMethodException e) {
                        throw new RuntimeException(e);
                    }
                }
                return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
            }
        }
        return serializerProvider.findNullValueSerializer(null);
    }
}

serialize使用序列化器序列化字段

createContextual创建序列化上下文,主要是明确使用的序列化策略或者其他方式

到这里基本就可以使用了

四、自定义序列化策略

从上面我们的策略是用接口的方式使用的,这里要实现这个接口

public class MyCustomizeNameStrategy implements MyStrategy {
    @Override
    public String desensitizationByPattern(String source) {
        if (StringUtils.isNotBlank(source)) {
            int s = source.length();
            int ss = source.lastIndexOf(".");
            if (ss == -1) {
                ss = 1;
                int sss = s - ss;
                return source.replaceAll("(\S{" + ss + "})\S{" + sss + "}", "$1" + SensitiveUtils.getStars(sss));
            } else {
                int sss = s - ss;
                return source.replaceAll("\S{" + ss + "}(\S{" + sss + "})", SensitiveUtils.getStars(ss) + "$1");
            }
        } else {
            return source;
        }
    }
}

这个是用来序列化姓名的,保留姓,这样就完成了,在使用注解 @CommonSensitive就可以使用了

五、规范化注解使用

在项目中经常要对不同性质的字段脱敏,例如邮箱,电话,身份证号码等,这些策略都不同,我们可以使用不同的序列化策略,但是这样使用不好的地方是我们要记住使用策略,为了方便使用,我们可以通过注解直接表明不同的注解表示不同的脱敏方式,无参的方式使用更加方便,这里选择使用邮件脱敏来说明

首先自定义一个邮件脱敏的规则:

public class MyEmailStrategy implements MyStrategy {
    @Override
    public String desensitizationByPattern(String source) {
        if (StringUtils.isNotBlank(source)) {
            int s = source.length();
            int ss = source.indexOf("@");
            int sss = s - ss;
            return source.replaceAll("\S{" + ss + "}(\S{" + sss + "})", SensitiveUtils.getStars(ss)+"$1");
        } else {
            return source;
        }
    }
}

然后通过使用我们定义的原始注解包装一下

@Documented@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@CommonSensitive(strategy = MyEmailStrategy.class)@JacksonAnnotationsInsidepublic @interface MyEmailSensitive {}

这样就完成了对字段属性的序列化注解,使用的策略正是上面我们定义的,这个注解还是无参的。

六、使用案例

先建立一个序列化对象

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@CommonSensitive(strategy = MyEmailStrategy.class)
@JacksonAnnotationsInside
public @interface MyEmailSensitive {
}
//上面我们使用不同的使用方式脱敏

//创建一个请求接口来实现脱敏操作

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {
    @PostMapping("/submit2")
    public Employee submit2(@RequestBody Employee employee) {
        log.info(JSON.toJSONString(employee));
        return employee;
    }
}

测试使用报文:

{    
  "name": "王斌强",
 "phone": "18637986236",    
 "email": "y.leffh@qymwmaej.yu"
}

打印日志:

{"email":"y.leffh@qymwmaej.yu","name":"王斌强","phone":"18637986236"}

返回报文:

{    
"name": "王*",    
"phone": "186****6236",    
"email": "*******@qymwmaej.yu"
}

至此,完成了使用注解的方式完成字段的脱敏操作。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1014482.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号