The first is to process the fields that need to be desensitized before serializing the entities, and then serialize them normally. The second is to process the fields to be desensitized during entity serialization.

Desensitization idea


Here we explore the first approach, which uses custom annotation-based log desensitization.

To desensitize data, it is basically to desensitize some key and a few fields, for example, an entity may only desensitize the password field, so you can use custom annotations, only need to add a annotation on the desensitization field, more convenient.

The overall idea is as follows:

When writing a log, clone a copy of the object to be printed before serialization, and then find out the fields adding desensitization custom annotations for the corresponding rules of processing conversion (for example, change “Andy Lau” to “Liu * Hua”), and then the object serialization operation.

Core code:

Define the annotation Desensitized. Java for identifying Desensitized fields

@Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Desensitized { /* Desensitization type(rule)*/ SensitiveTypeEnum type(); */ String isEffictiveMethod() default ""; }Copy the code

Desensitization type SensitiveTypeEnum. Java

Public enum SensitiveTypeEnum {/** Chinese SensitiveTypeEnum */ CHINESE_NAME, /** Id */ id, /** phone */ FIXED_PHONE, / cell phone number * * * / MOBILE_PHONE, / ADDRESS/ADDRESS * * * and * * E-mail * / EMAIL /, / * * * / BANK_CARD bank card, PASSWORD * / * * / PASSWORD; }Copy the code

Desensitizedutils.java to achieve desensitizedutils.java

Public class DesensitizedUtils {/** * get DesensitizedUtils ** @param javaBean * @return */ public static String getJson(Object) javaBean) { String json = null; if (null ! = javaBean) { try { if (javaBean.getClass().isInterface()) return json; Clone = objectutils. deepClone(javaBean); /* Clone = objectutils. deepClone(javaBean); ReferenceCounter = new HashSet<Integer>(); referenceCounter = new HashSet<Integer>(); / * desensitization on cloning entity for operation * / DesensitizedUtils. Replace (ObjectUtils. GetAllFields (clone), clone, referenceCounter); / * use fastjson clone object serialization of desensitization after * / json = json. ToJSONString (clone, SerializerFeature WriteMapNullValue, SerializerFeature.WriteNullListAsEmpty); /* Referencecounter.clear (); referenceCounter = null; } catch (Throwable e) { e.printStackTrace(); } } return json; } /** * Convert fields that need desensitization ** @param fields * @Param javaBean * @Param referenceCounter * @throws IllegalArgumentException * @throws IllegalAccessException */ private static void replace(Field[] fields, Object javaBean, Set<Integer> referenceCounter) throws IllegalArgumentException, IllegalAccessException { if (null ! = fields && fields.length > 0) { for (Field field : fields) { field.setAccessible(true); if (null ! = field && null ! = javaBean) { Object value = field.get(javaBean); if (null ! = value) { Class<? > type = value.getClass(); Int len = array.getLength (value); len = array.getLength (value); len = array.getLength (value); for (int i = 0; i < len; i++) { Object arrayObject = Array.get(value, i); if (isNotGeneralType(arrayObject.getClass(), arrayObject, referenceCounter)) { replace(ObjectUtils.getAllFields(arrayObject), arrayObject, referenceCounter); } } } else if (value instanceof Collection<? >) {// Recursively filter fields of Collection type Collection<? > c = (Collection<? >) value; Iterator<? > it = c.iterator(); while (it.hasNext()) { Object collectionObj = it.next(); if (isNotGeneralType(collectionObj.getClass(), collectionObj, referenceCounter)) { replace(ObjectUtils.getAllFields(collectionObj), collectionObj, referenceCounter); } } } else if (value instanceof Map<? ,? > < span style = "max-width: 100%; clear: both; min-height: 1em; ,? > m = (Map<? ,? >) value; Set<? > set = m.entrySet(); for (Object o : set) { Map.Entry<? ,? > entry = (Map.Entry<? ,? >) o; Object mapVal = entry.getValue(); if (isNotGeneralType(mapVal.getClass(), mapVal, referenceCounter)) { replace(ObjectUtils.getAllFields(mapVal), mapVal, referenceCounter); } } } else if (value instanceof Enum<? >) { continue; } else {if (! type.isPrimitive() && type.getPackage() ! = null && ! StringUtils.startsWith(type.getPackage().getName(), "javax.") && ! StringUtils.startsWith(type.getPackage().getName(), "java.") && ! StringUtils.startsWith(field.getType().getName(), "javax.") && ! StringUtils.startsWith(field.getName(), "java.") && referenceCounter.add(value.hashCode())) { replace(ObjectUtils.getAllFields(value), value, referenceCounter);  SetNewValueForField (javaBean, field, value); }}}} /** * Desensitization operation (convert fields to desensitization and set new values according to the rules) * Currently only supports String fields, if other types such as BigDecimal, Date, etc., are required, You can add * * @param javaBean * @param field * @param value * @throws IllegalAccessException */ public static void setNewValueForField(Object javaBean, Field field, Object Value) throws IllegalAccessException {// Process its own attribute Desensitized annotation = field.getAnnotation(Desensitized.class); if (field.getType().equals(String.class) && null ! = annotation && executeIsEffictiveMethod(javaBean, annotation)) { String valueStr = (String) value; if (StringUtils.isNotBlank(valueStr)) { switch (annotation.type()) { case CHINESE_NAME: { field.set(javaBean, DesensitizedUtils.chineseName(valueStr)); break; } case ID_CARD: { field.set(javaBean, DesensitizedUtils.idCardNum(valueStr)); break; } case FIXED_PHONE: { field.set(javaBean, DesensitizedUtils.fixedPhone(valueStr)); break; } case MOBILE_PHONE: { field.set(javaBean, DesensitizedUtils.mobilePhone(valueStr)); break; } case ADDRESS: { field.set(javaBean, DesensitizedUtils.address(valueStr, 8)); break; } case EMAIL: { field.set(javaBean, DesensitizedUtils.email(valueStr)); break; } case BANK_CARD: { field.set(javaBean, DesensitizedUtils.bankCard(valueStr)); break; } case PASSWORD: { field.set(javaBean, DesensitizedUtils.password(valueStr)); break; } } } } } }Copy the code

Desensitization test object userinfo.java

public class UserInfo{ @Desensitized(type = SensitiveTypeEnum.CHINESE_NAME) private String realName; @Desensitized(type = SensitiveTypeEnum.ID_CARD) private String idCardNo; @Desensitized(type = SensitiveTypeEnum.MOBILE_PHONE) private String mobileNo; private String account; @Desensitized(type = SensitiveTypeEnum.PASSWORD, isEffictiveMethod = "isEffictiveMethod") private String password; // setTers, getters omitted}Copy the code

Testing:

@test public void testUserInfoDesensitize() {BaseUserInfo BaseUserInfo = new BaseUserInfo().setrealName (" Hoodany ") .setidCardNo ("158199199013141120").setMobileno ("13579246810").setAccount("dannyhoo123456").setPassword("123456"); System.out.println(" before desensitization: "+ json.tojsonString (baseUserInfo)); System. The out. Println (" after desensitization: "+ DesensitizedUtils. GetJson (baseUserInfo)); }Copy the code

The above is only part of the code, all the code has been updated to github: github.com/DannyHoo/de…

The whole process more difficult object is cloned, the actual scenario to print a kaleidoscope of log object format, the object’s variable types are many, such as interface, enumeration, set, map, custom types, etc., in the process of implementation also tried many methods to achieve the entity’s deep cloning, such as serialized object first, again after deserialization get cloned objects, Or use a third-party clone tool class, are not well compatible with the actual environment of the object format, the source code is small in accordance with the existing needs, and there are many mistakes after the modification again and again, there may be a lot of unreasonable place, time is pressing, continue to optimize.

If you have any questions or suggestions about the whole implementation idea and method, please feel free to discuss them. If you have a better way, also hope you can share ~

Resources: blog.csdn.net/liuc0317/ar…


Data desensitization — Log Field desensitization Based on Java Custom Annotations by Hu Yuyang