5 changed files with 245 additions and 0 deletions
@ -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; |
|||
} |
|||
} |
Loading…
Reference in new issue