平时开发的过程中经常会遇到对一些敏感的字段进行脱敏处理,防止信息泄漏,如:邮箱、用户名、密码等;做为一个优秀的程序员我们不应该遇到这种问题时就做特殊处理,重复做相同的工作,所以我们应该写一个基础库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;文章来源:https://www.toymoban.com/news/detail-423188.html
GitHub地址:https://github.com/mingyang66/spring-parent文章来源地址https://www.toymoban.com/news/detail-423188.html
到了这里,关于解锁新技能《Java基于注解的脱敏实现组件SDK》的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!