新增数据脱敏过滤注解
This commit is contained in:
parent
86ca404dbf
commit
1140a6c333
|
@ -0,0 +1,24 @@
|
||||||
|
package com.ruoyi.common.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.ruoyi.common.config.serializer.SensitiveJsonSerializer;
|
||||||
|
import com.ruoyi.common.enums.DesensitizedType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据脱敏注解
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.FIELD)
|
||||||
|
@JacksonAnnotationsInside
|
||||||
|
@JsonSerialize(using = SensitiveJsonSerializer.class)
|
||||||
|
public @interface Sensitive
|
||||||
|
{
|
||||||
|
DesensitizedType desensitizedType();
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package com.ruoyi.common.config.serializer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
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.ruoyi.common.annotation.Sensitive;
|
||||||
|
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||||
|
import com.ruoyi.common.enums.DesensitizedType;
|
||||||
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据脱敏序列化过滤
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer
|
||||||
|
{
|
||||||
|
private DesensitizedType desensitizedType;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException
|
||||||
|
{
|
||||||
|
if (desensitization())
|
||||||
|
{
|
||||||
|
gen.writeString(desensitizedType.desensitizer().apply(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gen.writeString(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
|
||||||
|
throws JsonMappingException
|
||||||
|
{
|
||||||
|
Sensitive annotation = property.getAnnotation(Sensitive.class);
|
||||||
|
if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
|
||||||
|
{
|
||||||
|
this.desensitizedType = annotation.desensitizedType();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return prov.findValueSerializer(property.getType(), property);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否需要脱敏处理
|
||||||
|
*/
|
||||||
|
private boolean desensitization()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LoginUser securityUser = SecurityUtils.getLoginUser();
|
||||||
|
// 管理员不脱敏
|
||||||
|
return !securityUser.getUser().isAdmin();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.ruoyi.common.enums;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import com.ruoyi.common.utils.DesensitizedUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脱敏类型
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public enum DesensitizedType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 姓名,第2位星号替换
|
||||||
|
*/
|
||||||
|
USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码,全部字符都用*代替
|
||||||
|
*/
|
||||||
|
PASSWORD(DesensitizedUtil::password),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份证,中间10位星号替换
|
||||||
|
*/
|
||||||
|
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1** **** ****$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号,中间4位星号替换
|
||||||
|
*/
|
||||||
|
PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 电子邮箱,仅显示第一个字母和@后面的地址显示,其他星号替换
|
||||||
|
*/
|
||||||
|
EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 银行卡号,保留最后4位,其他星号替换
|
||||||
|
*/
|
||||||
|
BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车牌号码,包含普通车辆、新能源车辆
|
||||||
|
*/
|
||||||
|
CAR_LICENSE(DesensitizedUtil::carLicense);
|
||||||
|
|
||||||
|
private final Function<String, String> desensitizer;
|
||||||
|
|
||||||
|
DesensitizedType(Function<String, String> desensitizer)
|
||||||
|
{
|
||||||
|
this.desensitizer = desensitizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Function<String, String> desensitizer()
|
||||||
|
{
|
||||||
|
return desensitizer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.ruoyi.common.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脱敏工具类
|
||||||
|
*
|
||||||
|
* @author ruoyi
|
||||||
|
*/
|
||||||
|
public class DesensitizedUtil
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 密码的全部字符都用*代替,比如:******
|
||||||
|
*
|
||||||
|
* @param password 密码
|
||||||
|
* @return 脱敏后的密码
|
||||||
|
*/
|
||||||
|
public static String password(String password)
|
||||||
|
{
|
||||||
|
if (StringUtils.isBlank(password))
|
||||||
|
{
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
return StringUtils.repeat('*', password.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 车牌中间用*代替,如果是错误的车牌,不处理
|
||||||
|
*
|
||||||
|
* @param carLicense 完整的车牌号
|
||||||
|
* @return 脱敏后的车牌
|
||||||
|
*/
|
||||||
|
public static String carLicense(String carLicense)
|
||||||
|
{
|
||||||
|
if (StringUtils.isBlank(carLicense))
|
||||||
|
{
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
// 普通车牌
|
||||||
|
if (carLicense.length() == 7)
|
||||||
|
{
|
||||||
|
carLicense = StringUtils.hide(carLicense, 3, 6);
|
||||||
|
}
|
||||||
|
else if (carLicense.length() == 8)
|
||||||
|
{
|
||||||
|
// 新能源车牌
|
||||||
|
carLicense = StringUtils.hide(carLicense, 3, 7);
|
||||||
|
}
|
||||||
|
return carLicense;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,9 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||||
/** 下划线 */
|
/** 下划线 */
|
||||||
private static final char SEPARATOR = '_';
|
private static final char SEPARATOR = '_';
|
||||||
|
|
||||||
|
/** 星号 */
|
||||||
|
private static final char ASTERISK = '*';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取参数不为空值
|
* 获取参数不为空值
|
||||||
*
|
*
|
||||||
|
@ -163,6 +166,49 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||||
return (str == null ? "" : str.trim());
|
return (str == null ? "" : str.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换指定字符串的指定区间内字符为"*"
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param startInclude 开始位置(包含)
|
||||||
|
* @param endExclude 结束位置(不包含)
|
||||||
|
* @return 替换后的字符串
|
||||||
|
*/
|
||||||
|
public static String hide(CharSequence str, int startInclude, int endExclude)
|
||||||
|
{
|
||||||
|
if (isEmpty(str))
|
||||||
|
{
|
||||||
|
return NULLSTR;
|
||||||
|
}
|
||||||
|
final int strLength = str.length();
|
||||||
|
if (startInclude > strLength)
|
||||||
|
{
|
||||||
|
return NULLSTR;
|
||||||
|
}
|
||||||
|
if (endExclude > strLength)
|
||||||
|
{
|
||||||
|
endExclude = strLength;
|
||||||
|
}
|
||||||
|
if (startInclude > endExclude)
|
||||||
|
{
|
||||||
|
// 如果起始位置大于结束位置,不替换
|
||||||
|
return NULLSTR;
|
||||||
|
}
|
||||||
|
final char[] chars = new char[strLength];
|
||||||
|
for (int i = 0; i < strLength; i++)
|
||||||
|
{
|
||||||
|
if (i >= startInclude && i < endExclude)
|
||||||
|
{
|
||||||
|
chars[i] = ASTERISK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
chars[i] = str.charAt(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new String(chars);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 截取字符串
|
* 截取字符串
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue