spring boot实现数据脱敏+注解参数校验

数据脱敏实现

1.数据脱敏的概念

数据脱敏(Data Masking)是一种数据保护技术,用于隐藏或替换敏感数据,以保护数据的隐私和安全性,同时尽量保持数据的可用性和一定的格式保留。

数据脱敏的目的是在数据使用和共享的过程中,对敏感数据进行保护,防止敏感信息泄露、滥用或未经授权的访问。常见的敏感数据包括个人身份证号码、姓名、手机号码、银行账号、社会保险号等。
eg:

类型原始数据脱敏数据
手机13248765917132****5917
身份证530321199204074611530321**********11
银行卡9988002866797031998800********31

2.脱敏的好处

数据保护:通过脱敏技术,确保敏感数据在数据处理、存储和传输过程中得到有效保护,减少数据泄露和滥用的风险。

合规要求:许多行业和法规对于敏感数据的保护有着严格的要求,如GDPR(通用数据保护条例)、HIPAA(医疗保险可移植性和责任法案)等。数据脱敏可以帮助组织遵守相关法规和合规要求。

共享和分析:数据脱敏使得在共享数据或进行数据分析时,可以减少敏感信息的暴露,保护用户隐私,同时仍然能够进行有效的数据处理和分析。

测试和开发:在测试和开发过程中,使用脱敏数据可以减少对真实敏感数据的依赖,保护数据安全性,同时仍能进行系统功能和性能测试。

3.实现自定义脱敏

1.实现脱敏注解

@Target(ElementType.FIELD) // 标注在字段上
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside // 一般用于将其他的注解一起打包成"组合"注解
@JsonSerialize(using = SecretJsonSerializer.class) // 对标注注解的字段采用哪种序列化器进行序列化
public @interface SecretColumn {
    // 脱敏策略
    SecretStrategy strategy();
}

2.自定义序列化器

package com.weilai.mail.config;

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.weilai.mail.annotation.SecretColumn;
import com.weilai.mail.constants.SecretStrategy;
import java.io.IOException;
import java.util.Objects;

/**
 * 序列化器实现
 */
public class SecretJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {
 
    private SecretStrategy secretStrategy;
 
    /**
     * 步骤一
     * 方法来源于ContextualSerializer,获取属性上的注解属性,同时返回一个合适的序列化器
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
        // 获取自定义注解
        SecretColumn annotation = beanProperty.getAnnotation(SecretColumn.class);
        // 注解不为空,且标注的字段为String
        if(Objects.nonNull(annotation) && Objects.equals(String.class, beanProperty.getType().getRawClass())){
            this.secretStrategy = annotation.strategy();
            // 符合我们自定义情况,返回本序列化器,将顺利进入到该类中的serialize()方法中
            return this;
        }
        // 注解为空,字段不为String,寻找合适的序列化器进行处理
        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
    }
 
    /**
     * 步骤二
     * 方法来源于JsonSerializer<String>:指定返回类型为String类型,serialize()将修改后的数据返回
     */
    @Override
    public void serialize(String s, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        if(Objects.isNull(secretStrategy)){
            // 定义策略为空,返回原字符串
            jsonGenerator.writeString(s);
        }else {
            // 定义策略不为空,返回策略处理过的字符串
            jsonGenerator.writeString(secretStrategy.getDesensitizer().apply(s));
        }
    }
}

3.定义加密策略

@Getter
public enum SecretStrategy {
 
    /**
     * 用户名脱敏
     */
    USERNAME(str -> str.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
 
    /**
     * 身份证脱敏
     */
    ID_CARD(str -> str.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2")),
 
    /**
     * 手机号脱敏
     */
    PHONE(str -> str.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
 
    /**
     * 地址脱敏
     */
    ADDRESS(str -> str.replaceAll("(\\S{3})\\S{2}(\\S*)\\S{2}", "$1****$2****"));
 
    private final Function<String, String> desensitizer;
 
    SecretStrategy(Function<String, String> desensitizer){
        this.desensitizer = desensitizer;
    }

}

4.使用


  @SecretColumn(strategy = SecretStrategy.USERNAME)
    private String realName;
    @SecretColumn(strategy = SecretStrategy.ID_CARD)
    private String idNumber;

spring boot 注解参数校验

1 对于简单类型参数(非Bean),直接在参数前,使用注解添加约束规则。比如 @NotNull @Length 等 2 在类名前追加 @Validated 注解,否则添加的约束规则不生效。 3 方法被调用时,如果传入的实际参数与约束规则不符,会直接抛出 MethodArgumentNotValidException(Controller层) ConstraintViolationException (Service层),表明参数校验失败 4 对于Bean类型的参数,在Bean内部的各个字段上面追加约束注解,然后在方法的参数前面添加 @Valid 注解即可。

1.常用的校验注解

@Null(groups={Add.class}) 参数必须为null,group设置分组,默认为default
@NotNull 参数不为null
@NotEmpty 参数不为null"",集合不为空
@NotBlank 参数不为null""" ",只能作用字符串类型
@AssertFalse 被注释的元素必须是false
@AssertTrue 被注释的元素必须是true
@Min(value) 被注释的元素必须为一个数字  >=
@Max(value) 被注释的元素必须为一个数字 <= 
@DecimalMin("value")  >=
@DecimalMax("value") <= 
@NegativeOrZero <=0
@Range(min,max) 被注释的元素大小必须在指定的范围内 
@Size(min ,max) 被注释的元素大小必须在指定的范围内
@Email 被注释的元素必须是电子邮箱地址
@Past 被注释的元素必须是一个过去的日期
@PastOrPresent  被注释的元素必须是一个过去的时间
@Future 被注释的元素必须是一个将来的日期
@Pattern(regexp = "1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\\d{8}$")  被注释的元素必须是符合指定的正则表达式
@URL 被注释的元素必须是链接地址

2.依赖导入

<dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>

3.全局异常处理

当加上注解的字段不符合要求时则会抛出异常,所以我们要定义全局异常处理类来捕获这些异常

@RestControllerAdvice
public class ExceptionHandlers {
 
  @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handle(MethodArgumentNotValidException e) {
        return new Result(HttpStatus.HTTP_UNAUTHORIZED,e.getBindingResult().getFieldError().getDefaultMessage());
    }
 
    @ExceptionHandler(BindException.class)
    public Result handle(BindException e) {
        return new Result(HttpStatus.HTTP_UNAUTHORIZED,e.getBindingResult().getFieldError().getDefaultMessage());
    }
 
    @ExceptionHandler(ConstraintViolationException.class)
    public Result handle(ConstraintViolationException e) {
        StringBuffer sb = new StringBuffer();
        for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
            sb.append(violation.getMessage());
        }
        return new Result(HttpStatus.HTTP_UNAUTHORIZED,sb.toString());
    }
}

4.使用

package com.weilai.mail.pojo;

import com.baomidou.mybatisplus.annotation.*;
import com.weilai.mail.annotation.SecretColumn;
import com.weilai.mail.constants.Msg;
import com.weilai.mail.constants.SecretStrategy;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import javax.validation.constraints.Email;
import java.time.Year;
import java.util.Date;

/**
 * @author lxy
 */
@ToString
@AllArgsConstructor
@Data
@NoArgsConstructor
@TableName(value = "user",autoResultMap = true)
@ApiModel("用户类")
public class User {
    @TableId(value = "user_id",type = IdType.AUTO)
    @ApiModelProperty("用户id")
    private Integer id;
    @TableField("password")
    @ApiModelProperty("用户密码")
    private String password;
    @ApiModelProperty("用户昵称")
    @TableField("nickname")
    private String nickName;
    @ApiModelProperty("用户邮箱")
    @TableField("email")
    @Email(message = Msg.EMAILYTYPEERROR)
    private String email;
    @ApiModelProperty("地址")
    @TableField("address")
    private String address;
    @ApiModelProperty("真实姓名")
    @TableField("real_name")
    @SecretColumn(strategy = SecretStrategy.USERNAME)
    private String realName;
    @SecretColumn(strategy = SecretStrategy.ID_CARD)
    @ApiModelProperty("身份证号")
    @TableField("id_number")
    private String idNumber;
    @ApiModelProperty("头像链接")
    private String headImg;
    @TableField("create_time")
    @ApiModelProperty("创建时间")
    private Date createTime;
    @TableField("update_time")
    @ApiModelProperty("修改时间")
    private Date updateTime;
    @ApiModelProperty("用户权限")
    @TableField(value = "status")
    private Integer status;

    public User(String email, String password,String nickName, Date date, Date date1) {
        this.email = email;
        this.password = password;
        this.nickName = nickName;
        this.createTime =date;
        this.updateTime =date1;
    }
}

eger status;

public User(String email, String password,String nickName, Date date, Date date1) {
    this.email = email;
    this.password = password;
    this.nickName = nickName;
    this.createTime =date;
    this.updateTime =date1;
}

}

在这里插入图片描述



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值