使用AOP切面对返回的数据进行脱敏的问题

1.注解类

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

/**
 * @Author: xiaoxin
 * @Date: 2023/7/21 17:15
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface Encrypt {

    Type type() default Type.MOBILE_PHONE;

    enum Type {
        //用户id
        USER_ID,
        //中文名
        CHINESE_NAME,
        //身份证号
        ID_CARD,
        //座机号
        FIXED_PHONE,
        //手机号
        MOBILE_PHONE,
        //地址
        ADDRESS,
        //电子邮件
        EMAIL,
        //密码
        PASSWORD,
        //中国大陆车牌,包含普通车辆、新能源车辆
        CAR_LICENSE,
        //银行卡
        BANK_CARD,
        //字符串
        STR
    }

}

2.EncryptUtil工具

import cn.hutool.core.util.DesensitizedUtil;
import io.ctc.commons.tools.utils.StringUtils;

import java.lang.reflect.Field;

/**
 * @Author: xiaoxin
 * @Date: 2023/7/21 17:16
 */
public class EncryptUtil {


    public static void encryptFields(Object obj) {
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(Encrypt.class)) {
                Encrypt encryptAnnotation = field.getAnnotation(Encrypt.class);
                Encrypt.Type type = encryptAnnotation.type();
                field.setAccessible(true);
                try {
                    String value = (String) field.get(obj);
                    String encryptedValue = encryptValue(type, value);
                    field.set(obj, encryptedValue);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /***
     * 根据类型进行脱敏处理
     * @param type
     * @param value
     * @return
     */
    public static String encryptValue(Encrypt.Type type, String value) {
        StringBuffer sb = new StringBuffer();
        switch (type) {
            case USER_ID:
                sb.append(DesensitizedUtil.userId());
                break;
            case CHINESE_NAME:
                sb.append(DesensitizedUtil.chineseName(value));
                break;
            case ID_CARD:
                sb.append(DesensitizedUtil.idCardNum(value, 1, 2));
                break;
            case FIXED_PHONE:
                sb.append(DesensitizedUtil.fixedPhone(value));
                break;
            case MOBILE_PHONE:
                sb.append(DesensitizedUtil.mobilePhone(value));
                break;
            case ADDRESS:
                sb.append(DesensitizedUtil.address(value,6));
                break;
            case EMAIL:
                sb.append(DesensitizedUtil.email(value));
                break;
            case PASSWORD:
                sb.append(DesensitizedUtil.password(value));
                break;
            case CAR_LICENSE:
                sb.append(DesensitizedUtil.carLicense(value));
                break;
            case BANK_CARD:
                sb.append(DesensitizedUtil.bankCard(value));
                break;
            case STR:
                if (StringUtils.isNotBlank(encryptionStr(value))){
                    sb.append(encryptionStr(value));
                }
                break;

        }
        return sb.toString();
    }


    /***
     * 自定义字符串处理
     * @param str
     * @return
     */
    public static String encryptionStr(String str) {

        if (StringUtils.isBlank(str)){
            return "";
        }
        int length = str.length();
        if (length <= 4){
            return str;
        }
        // 替换的起始位置
        int startIndex = (length - 3) / 2;
        // 替换的结束位置
        int endIndex = startIndex + 3;
        // 替换为4个*
        String replacement = "****";

        StringBuilder sb = new StringBuilder(str);
        sb.replace(startIndex, endIndex, replacement);

        return sb.toString();
    }
}

3.EncryptAspect切面类

import io.ctc.commons.tools.utils.Result;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;


/**
 * @author xiaoxin
 */
@Aspect
@Component
public class EncryptAspect {


    protected Logger logger = LoggerFactory.getLogger(getClass());


    @Pointcut("@annotation(io.util.test.Encrypt)")
    public void encryptDataPointCut() {
    }


    /***
     * 后置增强,返回数据脱敏切面类,页面上有部分数据是不能对外展示的,此方法不支持反脱敏
     * 示例:原数据19879835555   脱敏后198****5555
     * @param point
     * @throws Throwable
     */
    @AfterReturning(value = "encryptDataPointCut()",returning = "returnValue")
    public void around(JoinPoint point, Object returnValue){

        logger.info("---------------后置增强~~~~对部分数据脱敏---------------");

        if (Objects.nonNull(returnValue)){

            //1.判断object是否可以转换为List<?>类型
            if (returnValue instanceof List<?>){
                List list = (List) returnValue;
                list.stream().forEach(a->{
                        EncryptUtil.encryptFields(a);
                });
            }else

            //2.result对象,属性有code、msg、data
            if (returnValue instanceof Result){
                try{
                    Result result = (Result) returnValue;
                    Object data = result.getData();
                    if (Objects.nonNull(data)){
                        if (data instanceof List<?>){
                            List list = (List) data;
                            list.stream().forEach(a->{
                                EncryptUtil.encryptFields(a);
                            });
                        }else {
                            EncryptUtil.encryptFields(data);
                        }
                    }
                }catch (ClassCastException e){
                    throw new ClassCastException("数据脱敏转换失败");
                }
            }else {
                EncryptUtil.encryptFields(returnValue);
            }
        }
    }
}

4.User对象(需要脱敏的属性)

import io.util.test.Encrypt;
import lombok.Data;

/**
 * 测试
 * @Author: xiaoxin
 * @Date: 2023/7/21 17:16
 */
@Data
public class User {

    @Encrypt(type = Encrypt.Type.USER_ID)
    private String user_id;

    @Encrypt(type = Encrypt.Type.CHINESE_NAME)
    private String chinese_name;

    @Encrypt(type = Encrypt.Type.ID_CARD)
    private String id_card;

    @Encrypt(type = Encrypt.Type.FIXED_PHONE)
    private String fixed_phone;

    @Encrypt(type = Encrypt.Type.MOBILE_PHONE)
    private String mobile_phone;

    @Encrypt(type = Encrypt.Type.ADDRESS)
    private String  address;

    @Encrypt(type = Encrypt.Type.EMAIL)
    private String email;

    @Encrypt(type = Encrypt.Type.PASSWORD)
    private String password;

    @Encrypt(type = Encrypt.Type.CAR_LICENSE)
    private String car_license;

    @Encrypt(type = Encrypt.Type.BANK_CARD)
    private String bank_card;

    @Encrypt(type = Encrypt.Type.STR)
    private String str;

}

5.下面为测试:

Controller

service

 结果:

 

统一返回结果就上面这样子的,controller上打上注解,实体类上根据类型打上注解就可以了。可以支持返回对象、List集合,分页的谁要的话在切面里写一下就好了,DesensitizedUtil是hutool的。

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值