java 序列化-注解-脱敏

5 篇文章 0 订阅

java 序列化-注解-脱敏

需求:

对于敏感字段需要加密脱敏操作;

实现方案:

通过序列化跟注解实现对指定的字段进行脱敏

序列化脱敏效果:
在这里插入图片描述

代码实现:

controller

package com.controller;

import com.pojo.Student;
import com.pojo.StudentVO;
import com.service.student.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author syh
 * @date 2023/5/614:07
 * @details 详情
 */
@RestController
@RequestMapping("/syh")
public class StudentController {


    @Autowired
    private StudentService studentService;


    @GetMapping("/{id}")
    public StudentVO searchStuByIdCard(@PathVariable("id") String id) {
        Student student = studentService.searchStuByIdCard(id);
        StudentVO studentVO = new StudentVO();
        studentVO.setName("好吃不贵");
        studentVO.setStudent(student);
        System.out.println("studentVO = " + studentVO);
        return studentVO;
    }

}

service

package com.service.student;


import com.baomidou.mybatisplus.extension.service.IService;
import com.pojo.Student;
import com.service.dealer.Dealer;

/**
 * @author syh
 * @date 2023/5/614:14
 * @details 详情
 */
public interface StudentService extends IService<Student> , Dealer {

    public Student searchStuByIdCard(String idCard);

}

package com.service.student.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mapper.StudentMapper;
import com.pojo.Student;
import com.pojo.Tasks;
import com.service.task.TasksTypeEnum;
import com.service.student.StudentService;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.UUID;

/**
 * @author syh
 * @date 2023/5/614:16
 * @details 详情
 */
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Override
    public Student searchStuByIdCard(String id) {
        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Student::getId, id);
        List<Student> students = studentMapper.selectList(wrapper);
        return students == null ? null : students.get(0);
    }


}

po

package com.pojo;

import com.annotation.DesensitizedAnnotation;
import com.baomidou.mybatisplus.annotation.TableField;
import com.serializer.DesensitizeTypeEnum;
import lombok.Data;

import java.beans.Transient;
import java.io.Serializable;

/**
 * @author syh
 * @date 2023/4/2619:36
 * @details 详情
 */
@Data
public class Student implements Serializable {

    private int id;
    @DesensitizedAnnotation(DesensitizeTypeEnum.CHINESE_NAME)
    private String name;
    private Integer age;
    private String address;
    @DesensitizedAnnotation(DesensitizeTypeEnum.ID_CARD)
    private String idCard;


}

package com.pojo;

import com.annotation.DesensitizedAnnotation;
import com.serializer.DesensitizeTypeEnum;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

/**
 * @author syh
 * @date 2023/6/14 14:20
 * @details 类描述
 */
@Data
public class StudentVO {

    @DesensitizedAnnotation(DesensitizeTypeEnum.CHINESE_NAME)
    private String name;

    private Student student;
}

enum

package com.serializer;

/**
 * @author syh
 * @date 2023/6/13 14:50
 * @details 类描述
 */
public enum DesensitizeTypeEnum {
    /**
     * 中文名字
     */
    CHINESE_NAME,

    /**
     * 身份证
     */
    ID_CARD;

}

Annotation 注解

package com.annotation;

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.serializer.DesensitizationAnnotationSerializer;
import com.serializer.DesensitizeTypeEnum;

import java.lang.annotation.*;

/**
 * @author syh
 * @date 2023/6/13 17:12
 * @details 脱敏注解
 */
@Inherited  //用于指定注解是否可以被继承。如果一个注解被@Inherited标记,那么当一个类继承了标有该注解的父类时,子类也会继承该注解。
@Documented  //生成的java文档中有注解的解释
@Retention(RetentionPolicy.RUNTIME)   //运行时
@Target(ElementType.FIELD)  //注解使用雨成员变量上
@JacksonAnnotationsInside
@JsonSerialize(using = DesensitizationAnnotationSerializer.class)
public @interface DesensitizedAnnotation {

    /**
     * 脱敏类型
     */
    DesensitizeTypeEnum value();
}

Serializer 序列化

package com.serializer;

import com.annotation.DesensitizedAnnotation;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.util.MaskUtil;

import java.io.IOException;
import java.util.Objects;

/**
 * @author syh
 * @date 2023/6/13 13:46
 * @details 类描述
 * JsonSerializer<String>  泛型String 针对string序列化 重写serializer
 * ContextualSerializer  重写type的创建方法,获取指定的type以及注解的value 给到不同的脱敏方式
 * 泛型的选择,可以使用object 通过对注解value的判断调整做到类型对应脱敏的方式;enum枚举是一个很好的选择;
 */
public class DesensitizationAnnotationSerializer extends JsonSerializer<String> implements ContextualSerializer {

    /**
     * 脱敏注解
     */
    private DesensitizeTypeEnum desensitizeTypeEnum;

    public DesensitizationAnnotationSerializer() {
    }

    public DesensitizationAnnotationSerializer(DesensitizeTypeEnum desensitizeTypeEnum) {
        this.desensitizeTypeEnum = desensitizeTypeEnum;
    }

    /**
     * 序列化脱敏
     *
     * @param value         Value to serialize; can <b>not</b> be null.
     * @param jsonGenerator Generator used to output resulting Json content
     * @param serializers   Provider that can be used to get serializers for
     *                      serializing Objects value contains, if any.
     * @throws IOException
     */
    @Override
    public void serialize(String value, JsonGenerator jsonGenerator, SerializerProvider serializers) throws IOException {
        if (StringUtils.isNotBlank(value)) {
            //脱敏  //根据注解选择脱敏的方式
            jsonGenerator.writeString(MaskUtil.mask(value, desensitizeTypeEnum));
        }
    }


    /**
     * 重新返回序列化的方式
     *
     * @param prov     Serializer provider to use for accessing config, other serializers
     * @param property Method or field that represents the property
     *                 (and is used to access value to serialize).
     *                 Should be available; but there may be cases where caller cannot provide it and
     *                 null is passed instead (in which case impls usually pass 'this' serializer as is)
     * @return
     * @throws JsonMappingException
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        if (ObjectUtils.isNotEmpty(property)) {
            if (Objects.equals(property.getType().getRawClass(), String.class)) {//可以不做判断,序列化只针对String(建议判断)
                //获取注解
                DesensitizedAnnotation annotation = property.getAnnotation(DesensitizedAnnotation.class);
                if (ObjectUtils.isNotEmpty(annotation)) {
                    //获取枚举脱敏规则
                    DesensitizeTypeEnum result = annotation.value();
                    //指定序列化方式
                    return new DesensitizationAnnotationSerializer(result);
                }
            }
            return prov.findContentValueSerializer(property.getType(), property);

        }
        return prov.findNullValueSerializer(property);

    }
}

util 脱敏工具类

package com.util;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.serializer.DesensitizeTypeEnum;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.baomidou.mybatisplus.core.toolkit.StringPool.STAR;

/**
 * @author syh
 * @date 2023/6/13 14:45
 * @details 脱敏工具类
 */
public class MaskUtil {


    /**
     * 返回脱敏方式
     *
     * @param value
     * @param desensitizeTypeEnum
     * @return
     */
    public static String mask(String value, DesensitizeTypeEnum desensitizeTypeEnum) {
        if (StringUtils.isBlank(value)) {
            return StringUtils.EMPTY;
        }
        switch (desensitizeTypeEnum) {
            case CHINESE_NAME:
                return maskName(value);
            case ID_CARD:
                return maskIdCard(value);
        }
        return null;
    }

    /**
     * 证件脱敏(身份证)
     *
     * @param value
     * @return
     */
    private static String maskIdCard(String value) {
        return maskString(value, 4, 4);
    }


    /**
     * 名字脱敏
     *
     * @param name
     * @return
     */
    private static String maskName(String name) {
        return maskString(name,1,0);
    }


    /**
     * 公共脱敏
     *
     * @param value
     * @param start 前几位不脱名
     * @param end   后几位不脱敏
     * @return
     */
    private static String maskString(String value, Integer start, Integer end) {
        if (StringUtils.isBlank(value)) {
            return StringUtils.EMPTY;
        }
        Integer length = value.length() - start - end;

        if (length <= 0) {
            return value;
        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(value.substring(0, start));
        for (int i = 0; i < length; i++) {
            stringBuilder.append(STAR);
        }
        //截取后几位
        stringBuilder.append(value.substring(value.length() - end));
        return stringBuilder.toString();
    }

    /**
     * 正则 碰撞脱敏
     * @param value
     * @param start 保留前几位
     * @param end   保留后几位
     * @return
     */
    private static String maskStringByPattern(String value, Integer start, Integer end){
       //正则规则(\S{3}{.*}\S{3})
        String regex="(\\S{"+start+"})(.*)(\\S{"+end+"})";
        //创建正则
        Pattern pattern = Pattern.compile(regex);
        //正则碰撞
        Matcher matcher = pattern.matcher(value);
        //碰撞结果
        boolean result = matcher.find();
        if(result){
            String group = matcher.group(2);
            StringBuilder stringBuilder=new StringBuilder();
            stringBuilder.append(matcher.group(1));
            for (int i = 0; i < group.length(); i++) {
                stringBuilder.append(STAR);
            }
            stringBuilder.append(matcher.group(3));
            return stringBuilder.toString();
        }
        return value;
    }


    public static void main(String[] args) {
        //String s = maskString("123456789", 3, 0);
        String s = maskStringByPattern("123456789", 3, 0);
        System.out.println(s);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值