通过反射注解实现数据脱敏

项目说明

进行一个简单的脱敏实际业务中可能会考虑list map等
@Desensitization:标记到需要脱敏的接口上

@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Desensitization {
}

@FiledDesensitization:标记到实体属性上

//作用域 作用于方法和类上
@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented //表示把注解生成在Javadoc中
public @interface FiledDesensitization {

    //默认为身份证号码脱敏
    MaskingTypeEnum type() default MaskingTypeEnum.ID_CARD;
}

MaskingTypeEnum 表示脱敏的类型 枚举

public enum MaskingTypeEnum {

    /*身份证号码*/
    ID_CARD,
    /*手机号码*/
    PHONE,
    /*地址*/
    EMAIL,
    /*姓名*/
    NAME
}

脱敏的类型 如(对idcard进行脱敏身份证):

@ApiModel(value = "TODO")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {
    @ApiModelProperty(value = "")
    private Integer id;

    @ApiModelProperty(value = "")
    private String username;

    @ApiModelProperty(value = "")
    @FiledDesensitization(type = MaskingTypeEnum.ID_CARD)
    private String idcard;

    @ApiModelProperty(value = "")
    private String telephon;

    @ApiModelProperty(value = "")
    private String email;

    @ApiModelProperty(value = "")
    private String password;
}

util

@Slf4j
public final class SensitiveInfoUtils {

    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
     *
     * @param
     * @return
     */
    public static String chineseName(String fullName) {
        if (StringUtils.isBlank(fullName)) {
            return "";
        }
        String name = StringUtils.left(fullName, 1);
        return StringUtils.rightPad(name, StringUtils.length(fullName), "*");
    }

    /**
     * [中文姓名] 只显示第一个汉字,其他隐藏为2个星号<例子:李**>
     *
     * @param familyName
     * @param givenName
     * @return
     */
    public static String chineseName(String familyName, String givenName) {
        if (StringUtils.isBlank(familyName) || StringUtils.isBlank(givenName)) {
            return "";
        }
        return chineseName(familyName + givenName);
    }

    /**
     * [身份证号] 显示最后四位,其他隐藏。共计18位或者15位。<例子:*************5762>
     *
     * @param id
     * @return
     */
    public static String idCardNum(String id) {
        if (StringUtils.isBlank(id)) {
            return "";
        }
        String num = StringUtils.right(id, 4);
        return StringUtils.leftPad(num, StringUtils.length(id), "*");
    }

    /**
     * [固定电话] 后四位,其他隐藏<例子:****1234>
     *
     * @param num
     * @return
     */
    public static String fixedPhone(String num) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        return StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*");
    }

    /**
     * [手机号码] 前三位,后四位,其他隐藏<例子:138******1234>
     *
     * @param num
     * @return
     */
    public static String mobilePhone(String num) {
        if (StringUtils.isBlank(num)) {
            return "";
        }
        return StringUtils.left(num, 3).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(num, 4), StringUtils.length(num), "*"), "***"));
    }

    /**
     * [地址] 只显示到地区,不显示详细地址;我们要对个人信息增强保护<例子:北京市海淀区****>
     *
     * @param address
     * @param sensitiveSize 敏感信息长度
     * @return
     */
    public static String address(String address, int sensitiveSize) {
        if (StringUtils.isBlank(address)) {
            return "";
        }
        int length = StringUtils.length(address);
        return StringUtils.rightPad(StringUtils.left(address, length - sensitiveSize), length, "*");
    }

    /**
     * [电子邮箱] 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示<例子:g**@163.com>
     *
     * @param email
     * @return
     */
    public static String email(String email) {
        if (StringUtils.isBlank(email)) {
            return "";
        }
        int index = StringUtils.indexOf(email, "@");
        if (index <= 1)
            return email;
        else
            return StringUtils.rightPad(StringUtils.left(email, 1), index, "*").concat(StringUtils.mid(email, index, StringUtils.length(email)));
    }

    /**
     * [银行卡号] 前六位,后四位,其他用星号隐藏每位1个星号<例子:6222600**********1234>
     *
     * @param cardNum
     * @return
     */
    public static String bankCard(String cardNum) {
        if (StringUtils.isBlank(cardNum)) {
            return "";
        }
        return StringUtils.left(cardNum, 6).concat(StringUtils.removeStart(StringUtils.leftPad(StringUtils.right(cardNum, 4), StringUtils.length(cardNum), "*"), "******"));
    }

    /**
     * [公司开户银行联号] 公司开户银行联行号,显示前两位,其他用星号隐藏,每位1个星号<例子:12********>
     *
     * @param code
     * @return
     */
    public static String cnapsCode(String code) {
        if (StringUtils.isBlank(code)) {
            return "";
        }
        return StringUtils.rightPad(StringUtils.left(code, 2), StringUtils.length(code), "*");
    }

}

切面

@Component
@Aspect
public class DesensitizationAspect {

      @Around("@annotation(Desensitization)")
    public Object doAnnotation(ProceedingJoinPoint pjp) throws Throwable {
        System.out.print("===方法执行前===");
        Object proceed = pjp.proceed();
        //如果返回的类型是List
        if ("java.util.ArrayList".equals(proceed.getClass().getName())) {
            List listResult = new ArrayList();
            List<?> list = (List) proceed;
            for (int i = 0; i < list.size(); i++) {
                Class<?> aClass = list.get(i).getClass();
                Field[] declaredFields1 = aClass.getDeclaredFields();
                for (Field field : declaredFields1) {
                    if (field.isAnnotationPresent(FiledDesensitization.class)) {
                        //setAccessible这行代码把对象上的私有字段为可以设置
                        field.setAccessible(true);
                        //如果属性值为null
                        if (field.get(list.get(i)) == null) {
                            break;
                        }
                        String value = field.get(list.get(i)).toString();
                        FiledDesensitization annotation = field.getAnnotation(FiledDesensitization.class);
                        MaskingTypeEnum type = annotation.type();
                        switch (type) {
                            case ID_CARD:
                                field.set(list.get(i), SensitiveInfoUtils.idCardNum(value));
                                break;
                            case NAME:
                                field.set(list.get(i), SensitiveInfoUtils.chineseName(value));
                            case PHONE:
                                field.set(list.get(i), SensitiveInfoUtils.mobilePhone(value));
                            case EMAIL:
                                field.set(list.get(i), SensitiveInfoUtils.email(value));
                                break;
                        }
                    }

                }
                listResult.add(list.get(i));
            }
            return listResult;
        }
        //如果返回的是单个实体
        Class<?> aClass = proceed.getClass();
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (declaredField.isAnnotationPresent(FiledDesensitization.class)) {
                //setAccessible这行代码把对象上的字段设置为public访问属性.
                declaredField.setAccessible(true);
                if (declaredField.get(proceed) == null) {
                    break;
                }
                String value = declaredField.get(proceed).toString();
                FiledDesensitization annotation = declaredField.getAnnotation(FiledDesensitization.class);
                MaskingTypeEnum type = annotation.type();
                switch (type) {
                    case ID_CARD:
                        declaredField.set(proceed, SensitiveInfoUtils.idCardNum(value));
                        break;
                    case NAME:
                        declaredField.set(proceed, SensitiveInfoUtils.chineseName(value));
                    case PHONE:
                        declaredField.set(proceed, SensitiveInfoUtils.mobilePhone(value));
                    case EMAIL:
                        declaredField.set(proceed, SensitiveInfoUtils.email(value));
                        break;
                }
            }
        }

        return proceed;
    }
}

contoller

@RestController
public class UserContoller {

    @Autowired
    private UserMapper userMapper;

    @Desensitization
    @GetMapping("/test")
    public User test(){
        User user = userMapper.selectByPrimaryKey(1L);
        return user;
    }

   @Desensitization
    @GetMapping("/test1")
    public List<User> test1() {
        User user = new User();
        user.setIdcard("43252219920724557");
        User user1 = new User();
        user1.setIdcard("43252219920724557");
        User user2 = new User();
        user2.setIdcard("43252219920724557");
        User user3 = new User();
        user3.setIdcard("43252219920724557");
        List<User> list = new ArrayList();
        list.add(user);
        list.add(user1);
        list.add(user2);
        list.add(user3);
        return list;
    }
}

启动类

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}

application.yml

server:
  port: 3333

spring:
  profiles:
    active: data
  application:
    name: boke-service
  cloud:
    alibaba:
      seata:
        # 自定义事务组名称需要与seata-server中的对应
        tx-service-group: fsp_tx_group
    nacos:
      discovery: #Nacos注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719

feign:
  hystrix:
    enabled: true

management:
  endpoints:
    web:
      exposure:
        include: "*"

logging:
  level:
    io:
      seata: info

application-data.yml

spring:
  datasource:
    #当前数据源操作类型
    type: com.alibaba.druid.pool.DruidDataSource
    #mysql驱动包
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/boke?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    username: root
    password: zz123456

mybatis:
  mapperLocations: classpath:mapping/*.xml
  #所有entity别名类所在包
  type-aliases-package: com.atguigu.huawei.dao

pom

<dependencies>
        <!--   sentinel     -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--nacos-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--seata-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>seata-all</artifactId>
                    <groupId>io.seata</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-all</artifactId>
            <version>0.9.0</version>
        </dependency>
        <!--feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--web-actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--mysql-druid-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--lombok依赖-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--lombok依赖-->


        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.8.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-staticdocs</artifactId>
            <version>2.5.0</version>
        </dependency>
        <!--swagger2-->
    </dependencies>

父pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atgui.huawei.</groupId>
    <artifactId>boke</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-alibaba-boke</module>
    </modules>

    <!-- 统一管理jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>8.0.18</mysql.version>
        <druid.version>1.1.21</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version  -->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring springcloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring springcloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <!--<plugins>-->
        <!--<plugin>-->
        <!--<groupId>org.springframework.boot</groupId>-->
        <!--<artifactId>spring-boot-maven-plugin</artifactId>-->
        <!--<configuration>-->
        <!--<fork>true</fork>-->
        <!--<addResources>true</addResources>-->
        <!--</configuration>-->
        <!--</plugin>-->
        <!--</plugins>-->
    </build>



</project>

验证:
开启访问test
在这里插入图片描述
访问test1
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值