desensibilización de anotaciones java

Breve introducción

Con la popularidad de la era de Internet, la información del usuario se está volviendo cada vez más importante. También necesitamos desensibilizar y cifrar la información del usuario en el proceso de desarrollo de software. Para tareas más complicadas, explique personalmente cómo lograr la desensibilización de anotaciones. Admite llamadas estáticas y aop interceptación unificada para realizar la desensibilización o el retorno cifrado.

Explicación del código

Clase de enumeración de desensibilización

    Defina la clase de enumeración, maneje toda la desensibilización y el cifrado, etc., mientras que es extensible, aquí solo hay un método de llamada anotado, para escribir muestras. DesensitizationEnum Si necesita otros métodos de desensibilización o cifrado, solo necesita agregar los siguientes tipos de enumeración

package com.lgh.common.sensitive;


import com.lgh.common.utils.MaskUtils;

import java.lang.reflect.Method;

/**
 * 若需要新定义一个扫描规则,这里添加即可
 *
 * @author lgh
 * @version 1.0
 * @date 2021/1/17
 */
public enum DesensitizationEnum {
    
    

    // 执行类和脱敏方法名
    PHONE(MaskUtils.class, "maskPhone", new Class[]{
    
    String.class});

     private Class<?> clazz;
     private Method method;

    DesensitizationEnum(Class<?> target, String method, Class[] paramTypes) {
    
    
        this.clazz = target;
        try {
    
    
            this.method = target.getDeclaredMethod(method, paramTypes);
        } catch (NoSuchMethodException e) {
    
    
             e.printStackTrace();
        }
    }
    public Method getMethod() {
    
    
        return method;
    }
}

Herramienta de desensibilización

package com.lgh.common.utils;

import org.springframework.util.StringUtils;

/**
 * @author lgh
 * @version 1.0
 * @date 2021/1/17
 */
public class MaskUtils {
    
    

    public static String maskPhone(String phone){
    
    
        if(StringUtils.isEmpty(phone) || phone.length() < 8){
    
    
            return phone;
        }
        return phone.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
    }
}

Escritura de clase de anotación

Esta clase se puede agregar al atributo de clase que debe desensibilizarse para lograr la desensibilización. Específicamente, la anotación se atraviesa de forma recursiva y la función de desensibilización se realiza a través del mecanismo de reflexión.

package com.lgh.common.sensitive;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 参数定义注解类
 * @author linguohu
 * @version 1.0
 * @date 2021/1/17
 **/
@Target({
    
    ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SensitiveValid {
    
    
    DesensitizationEnum type();
}

Herramientas de desensibilización

Enunciado especial, cuando recurrimos, es una recursividad de índice y habrá un bucle infinito. Por ejemplo, un objeto se refiere a un objeto y se hace referencia a una dirección circular, por lo que habrá un bucle infinito. Hay 10 niveles de recursividad Por lo general, no permitimos objetos tan profundos.

package com.lgh.common.utils;

import com.lgh.common.sensitive.DesensitizationEnum;
import com.lgh.common.sensitive.SensitiveValid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;

/**
 * 对象脱敏工具
 *
 * @author lgh
 * @version 1.0
 * @date 2021/1/17
 */
public class DesensitizationUtils {
    
    
    private static final Logger log = LoggerFactory.getLogger(DesensitizationUtils.class);

    private DesensitizationUtils() {
    
    
    }

    /**
     * 扫描对象注解,脱敏,最高层次8层
     *
     * @param obj
     */
    public static void format(Object obj) {
    
    
        DesensitizationUtils.formatMethod(obj, 10);
    }

    /**
     * 递归遍历数据,因为可能有对象地址应用导致循环问题,同时设置莫名奇妙的异常,所以设置递归层次,一般不要超过10层
     *
     * @param obj   需要反射对象
     * @param level 递归层次,必须输入
     */
    private static void formatMethod(Object obj, int level) {
    
    
        if (obj == null || isPrimitive(obj.getClass()) || level <= 0) {
    
    
            return;
        }
        if (obj.getClass().isArray()) {
    
    
            for (Object object : (Object[]) obj) {
    
    
                formatMethod(object, level--);
            }
        } else if (Collection.class.isAssignableFrom(obj.getClass())) {
    
    
            for (Object o : ((Collection) obj)) {
    
    
                formatMethod(o, level--);
            }
        } else if (Map.class.isAssignableFrom(obj.getClass())) {
    
    
            for (Object o : ((Map) obj).values()) {
    
    
                formatMethod(o, level--);
            }
        } else {
    
    
            objFormat(obj, level);
        }
    }

    /**
     * 只有对象才格式化数据
     *
     * @param obj
     * @param level
     */
    private static void objFormat(Object obj, int level) {
    
    
        for (Field field : obj.getClass().getDeclaredFields()) {
    
    
            try {
    
    
                if (isPrimitive(field.getType())) {
    
    
                    SensitiveValid sensitiveValid = field.getAnnotation(SensitiveValid.class);
                    if (sensitiveValid != null) {
    
    
                        ReflectionUtils.makeAccessible(field);
                        DesensitizationEnum desensitizationEnum = sensitiveValid.type();
                        Object fieldV = desensitizationEnum.getMethod().invoke(null, field.get(obj));
                        ReflectionUtils.setField(field, obj, fieldV);
                    }
                } else {
    
    
                    ReflectionUtils.makeAccessible(field);
                    Object fieldValue = ReflectionUtils.getField(field, obj);
                    if (fieldValue == null) {
    
    
                        continue;
                    }
                    formatMethod(fieldValue, level - 1);
                }
            } catch (Exception e) {
    
    
                log.error("脱敏数据处理异常", e);
            }
        }
    }

    /**
     * 基本数据类型和String类型判断
     *
     * @param clz
     * @return
     */
    public static boolean isPrimitive(Class<?> clz) {
    
    
        try {
    
    
            if (String.class.isAssignableFrom(clz) || clz.isPrimitive()) {
    
    
                return true;
            } else {
    
    
                return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
            }
        } catch (Exception e) {
    
    
            return false;
        }
    }
}

La realización de la desensibilización AOP

Aop programación enchufable, para evitar operaciones innecesarias, así que escriba una anotación de clase controlable EnableDesensitization

package com.lgh.common.sensitive;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 方法返回值拦截器,需要注解才生效
 * @author lgh
 * @version 1.0
 * @date 2021/1/17
 **/
@Target({
    
    ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableDesensitization {
    
    
}

Finalmente lograr interceptar aop

package com.lgh.common.sensitive;

import com.lgh.common.utils.DesensitizationUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.aspectj.lang.annotation.Aspect;
import java.lang.reflect.Method;

/**
 * @author lgh
 * @version 1.0
 * @date 2021/1/17
 */
@Aspect
@Configuration
public class SensitiveAspect {
    
    
    public static final String ACCESS_EXECUTION = "execution(* com.lgh.controller..*.*(..))";
    /**
     * 注解脱敏处理
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(ACCESS_EXECUTION)
    public Object sensitiveClass(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        return sensitiveFormat(joinPoint);
    }

    /**
     * 插拔式注解统一拦截器。@{link EnableDesensitization } 和 @SensitiveValid
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    public Object sensitiveFormat(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        Object obj = joinPoint.proceed();
        if (obj == null || DesensitizationUtils.isPrimitive(obj.getClass())) {
    
    
            return obj;
        }
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        EnableDesensitization desensitization = joinPoint.getTarget().getClass().getAnnotation(EnableDesensitization.class);
        if (desensitization != null || method.getAnnotation(EnableDesensitization.class) != null) {
    
    
            DesensitizationUtils.format(obj);
        }
        return obj;
    }
}

Ejercicio de combate real

El objeto UserDetail que viví en el capítulo anterior agregó el campo del teléfono y agregó un comentario, de la siguiente manera:

package com.lgh.common.authority.entity;

import com.lgh.common.sensitive.DesensitizationEnum;
import com.lgh.common.sensitive.SensitiveValid;

public class UserDetail {
    
    
    private long id;
    private String name;
    @SensitiveValid(type = DesensitizationEnum.PHONE)
    private String phone;

    public long getId() {
    
    
        return id;
    }

    public void setId(long id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void setPhone(String phone) {
    
    
        this.phone = phone;
    }

    public String getPhone() {
    
    
        return phone;
    }
}

A continuación, inicie la anotación en el controlador.

@GetMapping("/detail")
    @EnableDesensitization
    public IResult<UserDetail> getUser(@AuthenticationPrincipal UserDetail userDetail) {
    
    
        return CommonResult.successData(userDetail);
    }

Listo, implementemos la operación de acceso
Inserte la descripción de la imagen aquí

Enlaces

github

Supongo que te gusta

Origin blog.csdn.net/soft_z1302/article/details/112756482
Recomendado
Clasificación