From d9062f8b060a6f70108d1e0763b3981a05469666 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: 星期一, 08 四月 2024 13:15:42 +0800
Subject: [PATCH] 新增数据脱敏过滤注解

---
 src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java                 |   49 +++++++++
 src/main/java/com/ruoyi/framework/aspectj/lang/enums/DesensitizedType.java |   59 +++++++++++
 src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Sensitive.java   |   24 ++++
 src/main/java/com/ruoyi/common/utils/StringUtils.java                      |   46 +++++++++
 src/main/java/com/ruoyi/framework/config/SensitiveJsonSerializer.java      |   67 +++++++++++++
 5 files changed, 245 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java b/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java
new file mode 100644
index 0000000..f8a4c02
--- /dev/null
+++ b/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java
@@ -0,0 +1,49 @@
+package com.ruoyi.common.utils;
+
+/**
+ * 鑴辨晱宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+public class DesensitizedUtil
+{
+    /**
+     * 瀵嗙爜鐨勫叏閮ㄥ瓧绗﹂兘鐢�*浠f浛锛屾瘮濡傦細******
+     *
+     * @param password 瀵嗙爜
+     * @return 鑴辨晱鍚庣殑瀵嗙爜
+     */
+    public static String password(String password)
+    {
+        if (StringUtils.isBlank(password))
+        {
+            return StringUtils.EMPTY;
+        }
+        return StringUtils.repeat('*', password.length());
+    }
+
+    /**
+     * 杞︾墝涓棿鐢�*浠f浛锛屽鏋滄槸閿欒鐨勮溅鐗岋紝涓嶅鐞�
+     *
+     * @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;
+    }
+}
diff --git a/src/main/java/com/ruoyi/common/utils/StringUtils.java b/src/main/java/com/ruoyi/common/utils/StringUtils.java
index 215d115..fc6c6b5 100644
--- a/src/main/java/com/ruoyi/common/utils/StringUtils.java
+++ b/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 瀛楃涓�
diff --git a/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Sensitive.java b/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Sensitive.java
new file mode 100644
index 0000000..ae121fa
--- /dev/null
+++ b/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();
+}
diff --git a/src/main/java/com/ruoyi/framework/aspectj/lang/enums/DesensitizedType.java b/src/main/java/com/ruoyi/framework/aspectj/lang/enums/DesensitizedType.java
new file mode 100644
index 0000000..619f5a5
--- /dev/null
+++ b/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")),
+
+    /**
+     * 瀵嗙爜锛屽叏閮ㄥ瓧绗﹂兘鐢�*浠f浛
+     */
+    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;
+    }
+}
diff --git a/src/main/java/com/ruoyi/framework/config/SensitiveJsonSerializer.java b/src/main/java/com/ruoyi/framework/config/SensitiveJsonSerializer.java
new file mode 100644
index 0000000..a0ada33
--- /dev/null
+++ b/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;
+        }
+    }
+}

--
Gitblit v1.9.3