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

news2024/11/13 11:10:39

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的。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/815805.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java连接sftp服务器实现上传下载

一、准备SFTP服务器 我目前使用的是freeSSHd.exe,下载后按照步骤一步步安装&#xff0c;最后俩弹窗&#xff0c;第一个选是&#xff0c;第二个选否。 二、基础配置 双击打开安装好的程序&#xff0c;在右下角找到图标&#xff0c;右键&#xff0c;setting 按照步骤配置 …

根据端口号查找服务位置

已知服务的IP和端口&#xff0c;查找该服务所在位置 1、打开命令提示符&#xff08;CMD&#xff09; WINR快捷键打开运行对话框&#xff0c;输入CMD&#xff0c;回车即可。 2、找到对应的PID或程序名称 输入netstat -ano|findstr 端口号&#xff0c;回车找到对应的PID&…

msvcp140.dll丢失怎么修复?《绝地求生》报错msvcp140.dll丢失修复方法

在我运行《绝地求生》游戏的时候&#xff0c;出现msvcp140.dll丢失的错误提示时&#xff0c;感到有些困扰和不安&#xff0c;不知道该如何解决这个问题。同时&#xff0c;我也会担心这个问题会对我使用电脑产生什么不利影响。在尝试解决这个问题之前&#xff0c;我开始意识到我…

ScrumMaster认证课-PSM,了解一下

在敏捷学习的道路上继续前行&#xff0c;Leangoo领歌的PSM课程已经开启&#xff0c;认证全球认可&#xff0c;还不用续证&#xff0c;可以了解一下。 Scrum是目前运用最为广泛的敏捷开发方法&#xff0c;是一个轻量级的项目管理和产品研发管理框架&#xff0c;旨在最短时间内交…

Java课题笔记~数据库连接池

一、数据库连接池 1.1 数据库连接池简介 数据库连接池是个容器&#xff0c;负责分配、管理数据库连接(Connection) 它允许应用程序重复使用一个现有的数据库连接&#xff0c;而不是再重新建立一个&#xff1b; 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数…

前端Vue入门-day05-自定义指令、插槽、路由入门

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 自定义指令 基本语法 (全局&局部注册) 全局注册 局部注册 指令的值 v-loading 指令封装 插槽 …

电子贺卡蓝牙芯片,支U盘/SD卡音频播放蓝牙IC,WT2605-32N-L009

喜庆的时刻&#xff0c;向亲朋好友送上一份特别的祝福&#xff0c;是传递情谊、增进感情的最佳方式。然而&#xff0c;传统贺卡的简单文字和图片已经无法满足我们对个性化、创意化的需求。现在&#xff0c;深圳唯创知音&#xff0c;带来了一款颠覆传统贺卡的全新蓝牙BLE方案——…

使用Windbg分析从系统应用程序日志中找到的系统自动生成的dump文件去排查问题

目录 1、尝试将Windbg附加到目标进程上进行动态调试&#xff0c;但Windbg并没有捕获到 2、在系统应用程序日志中找到了系统在程序发生异常时自动生成的dump文件 2.1、查看应用程序日志的入口 2.2、在应用程序日志中找到系统自动生成的dump文件 3、使用Windbg静态分析dump文…

ardupilot 如何安装intelhex模块

目录 文章目录 目录摘要1.下载资源1.下载需要的软件2.编译带bt的固件摘要 本节主要记录ardupilot如何安装intelhex模块,实现编译ardupilot的bootloader文件并生成bootloader文件和固件合并的.hex文件。 1.下载资源 1.下载需要的软件 下载网址 intelhex-2.3.0.tar.gz 下载…

笔记本触摸板没反应怎么办?只需要4个方法!快速解决!

“大家知道为什么笔记本触摸板没反应吗&#xff1f;我的鼠标不见了现在触摸板也没反应&#xff0c;根本就用不了电脑了&#xff0c;有什么方法可以解决吗&#xff1f;” 触摸板是笔记本电脑上最重要的输入设备之一&#xff0c;它可以提供便捷的操作方式。对于很多朋友来说&…

SQL 执行计划管理(SPM)

一、SPM 需求背景 任何数据库应用程序的性能在很大程度上都依赖于查询执行&#xff0c;尽管优化器无需用户干预就可以评估最佳计划&#xff0c;但是 SQL 语句的执行计划仍可能由于以下多种原因发生意外更改&#xff1a;版本升级、重新收集优化器统计信息、改变优化器参数或模式…

Golang之路---01 Golang VS Code创建项目

Golang VS Code创建项目 代码组织 Golang使用包和模块来组织代码&#xff0c;包对应到文件系统就是文件夹&#xff0c;模块就是xxx.go的go源文件。一个包中会有多个模块&#xff0c;或者多个子包。 早期使用的是gopath来管理项目&#xff0c;不方便&#xff0c;比较麻烦&…

QWidget窗口类

QWidget窗口类 设置父对象窗口位置窗口尺寸窗口标题和图标信号槽函数例子1例子3例子3 设置父对象 // 构造函数 QWidget::QWidget(QWidget *parent nullptr, Qt::WindowFlags f Qt::WindowFlags());// 公共成员函数 // 给当前窗口设置父对象 void QWidget::setParent(QWidget…

中药配方煎药-亿发智能中药汤剂煎煮系统,智慧中药房的数字化升级

随着中药的普及&#xff0c;在治病、养生等方面都发挥这积极作用&#xff0c;但中药煎煮过程繁琐&#xff0c;如果有所差错将会影响药品的药性。为了满足当今用户对中药的需求&#xff0c;增强生产效率和业务水平&#xff0c;亿发中药煎配智能管理系统应运而生&#xff0c;为用…

线程同步问题——锁

文章目录 线程同步互斥锁&#xff08;互斥量&#xff09;相关操作函数应用 死锁读写锁相关操作函数 线程同步 临界区——代码 临界数据——共享数据 原子操作&#xff1a;不可以被其他操作打断 必须的&#xff0c;用以保证数据的安全性 实现线程同步的方式&#xff1a; 互斥量…

第十四章、【Linux】磁盘配额与进阶文件系统管理

14.1 磁盘配额 &#xff08;Quota&#xff09; 的应用与实作 14.1.1 什么是 Quota 在 Linux 系统中&#xff0c;由于是多用户多任务的环境&#xff0c;所以会有多人共同使用一个硬盘空间的情况发生&#xff0c; 如果其中有少数几个使用者大量的占掉了硬盘空间的话&#xff0c…

数字人会成为文旅行业的新增量吗?写实数字人定制包含哪些技术?

近年来&#xff0c;各大文旅机构均在围绕数字人展开了文旅营销创作&#xff0c;凭借着写实数字人定制技术&#xff0c;将数字人的人设、功能以及才艺得到创新&#xff0c;并由此在文旅形态上展开了诸多尝试。 比如会唱山歌多才多艺的数字人刘三姐&#xff0c;使用多种语言推介…

【Docker】Docker的工具实践及root概念和Docker容器安全性设置的详细讲解

前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 &#x1f4d5;作者简介&#xff1a;热…

css滤镜:drop-shadow

一、用法 drop-shadow( offset-x offset-y blur-radius spread-radius color ) offset-x&#xff1a;此参数设置图像的水平偏移。正值将创建右侧的偏移量&#xff0c;负值将创建左侧的偏移量。offset-y&#xff1a;此参数设置图像的垂直偏移。正值创建到底部的偏移量&#xff…

公众号套图制作教你打造独特商品宣传海报风格

在公众号的运营中&#xff0c;一个精美的海报设计可以吸引更多的关注和转发&#xff0c;提升文章的曝光度和传播效果。然而&#xff0c;对于没有设计经验的人来说&#xff0c;制作一个令人惊艳的海报可能是一项挑战。但是&#xff0c;现在有了乔拓云这个强大的工具&#xff0c;…