RuoYi
2024-04-08 d9062f8b060a6f70108d1e0763b3981a05469666
新增数据脱敏过滤注解
已修改1个文件
已添加4个文件
245 ■■■■■ 文件已修改
src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/utils/StringUtils.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Sensitive.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/framework/aspectj/lang/enums/DesensitizedType.java 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/framework/config/SensitiveJsonSerializer.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java
¶Ô±ÈÐÂÎļþ
@@ -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;
    }
}
src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -23,6 +23,9 @@
    /** ä¸‹åˆ’线 */
    private static final char SEPARATOR = '_';
    /** æ˜Ÿå· */
    private static final char ASTERISK = '*';
    /**
     * èŽ·å–å‚æ•°ä¸ä¸ºç©ºå€¼
     * 
@@ -164,6 +167,49 @@
    }
    /**
     * æ›¿æ¢æŒ‡å®šå­—符串的指定区间内字符为"*"
     *
     * @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);
    }
    /**
     * æˆªå–字符串
     * 
     * @param str å­—符串
src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Sensitive.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.framework.aspectj.lang.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.framework.aspectj.lang.enums.DesensitizedType;
import com.ruoyi.framework.config.SensitiveJsonSerializer;
/**
 * æ•°æ®è„±æ•æ³¨è§£
 *
 * @author ruoyi
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@JacksonAnnotationsInside
@JsonSerialize(using = SensitiveJsonSerializer.class)
public @interface Sensitive
{
    DesensitizedType desensitizedType();
}
src/main/java/com/ruoyi/framework/aspectj/lang/enums/DesensitizedType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,59 @@
package com.ruoyi.framework.aspectj.lang.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;
    }
}
src/main/java/com/ruoyi/framework/config/SensitiveJsonSerializer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@
package com.ruoyi.framework.config;
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.utils.SecurityUtils;
import com.ruoyi.framework.aspectj.lang.annotation.Sensitive;
import com.ruoyi.framework.aspectj.lang.enums.DesensitizedType;
import com.ruoyi.framework.security.LoginUser;
/**
 * æ•°æ®è„±æ•åºåˆ—化过滤
 *
 * @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;
        }
    }
}