浏览代码

feat: 支持 vo 返回的脱敏

gaibu 2 年之前
父节点
当前提交
5c8e41b847
共有 21 个文件被更改,包括 457 次插入116 次删除
  1. 19 2
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/pom.xml
  2. 10 30
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/Desensitize.java
  3. 33 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/RegexDesensitize.java
  4. 39 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/SliderDesensitize.java
  5. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/BankCardDesensitize.java
  6. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/CarLicenseDesensitize.java
  7. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/ChineseNameDesensitize.java
  8. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/EmailDesensitize.java
  9. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/FixedPhoneDesensitize.java
  10. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/IdCardDesensitize.java
  11. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/PasswordDesensitize.java
  12. 21 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/PhoneNumberDesensitize.java
  13. 0 24
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/constants/DesensitizeConstants.java
  14. 0 49
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/enums/DesensitizationStrategyEnum.java
  15. 0 10
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/DefaultDesensitizationHandler.java
  16. 1 1
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/DesensitizationHandler.java
  17. 34 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/DesensitizationHandlerHolder.java
  18. 13 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/RegexDesensitizationHandler.java
  19. 39 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/SliderDesensitizationHandler.java
  20. 76 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/serializer/StringDesensitizeSerializer.java
  21. 25 0
      yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/test/java/cn/iocoder/yudao/framework/desensitize/handler/DesensitizationHandlerTest.java

+ 19 - 2
yudao-framework/yudao-spring-boot-starter-biz-desensitize/pom.xml

@@ -4,9 +4,9 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
-        <groupId>cn.iocoder.boot</groupId>
         <artifactId>yudao-framework</artifactId>
-        <version>1.6.6-snapshot</version>
+        <groupId>cn.iocoder.boot</groupId>
+        <version>${revision}</version>
     </parent>
 
     <artifactId>yudao-spring-boot-starter-biz-desensitize</artifactId>
@@ -22,5 +22,22 @@
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-common</artifactId>
         </dependency>
+
+        <!-- jackson -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+
+        <!-- Test 测试相关 -->
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>

+ 10 - 30
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/Desensitize.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.framework.desensitize.annotation;
 
-import cn.iocoder.yudao.framework.desensitize.enums.DesensitizationStrategyEnum;
 import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandler;
+import cn.iocoder.yudao.framework.desensitize.serializer.StringDesensitizeSerializer;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
@@ -11,40 +13,18 @@ import java.lang.annotation.Target;
 
 
 /**
- * Desensitize 注解配置会覆盖 DesensitizationStrategyEnum 配置
+ * Desensitize 顶级脱敏注解
  */
-@Target({ElementType.FIELD})
-@Retention(RetentionPolicy.RUNTIME)
 @Documented
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@JsonSerialize(using = StringDesensitizeSerializer.class)
 public @interface Desensitize {
 
-    /**
-     * 脱敏策略
-     */
-    DesensitizationStrategyEnum strategy();
-
-    /**
-     * 脱敏替换字符
-     */
-    String replacer();
-
-    /**
-     * 正则表达式
-     */
-    String regex();
-
-    /**
-     * 前缀保留长度
-     */
-    int preKeep();
-
-    /**
-     * 后缀保留长度
-     */
-    int suffixKeep();
-
     /**
      * 脱敏处理器
      */
-    Class<? extends DesensitizationHandler> handler();
+    Class<? extends DesensitizationHandler> desensitizationHandler();
+
 }

+ 33 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/RegexDesensitize.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.framework.desensitize.annotation;
+
+import cn.iocoder.yudao.framework.desensitize.handler.RegexDesensitizationHandler;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 正则脱敏注解
+ */
+@Documented
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@Desensitize(desensitizationHandler = RegexDesensitizationHandler.class)
+public @interface RegexDesensitize {
+    /**
+     * 匹配的正则表达式(默认匹配所有)
+     */
+    String regex() default "^[\\s\\S]*$";
+
+    /**
+     * 替换规则,会将匹配到的字符串全部替换成 replacer
+     * 例如:regex=123; replacer=******
+     * 原始字符串 123456789
+     * 脱敏后字符串 ******456789
+     */
+    String replacer() default "******";
+}

+ 39 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/SliderDesensitize.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.desensitize.annotation;
+
+import cn.iocoder.yudao.framework.desensitize.handler.SliderDesensitizationHandler;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 滑动脱敏注解
+ */
+@Documented
+@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@Desensitize(desensitizationHandler = SliderDesensitizationHandler.class)
+public @interface SliderDesensitize {
+
+    /**
+     * 后缀保留长度
+     */
+    int suffixKeep() default 0;
+
+    /**
+     * 替换规则,会将前缀后缀保留后,全部替换成 replacer
+     * 例如:prefixKeep = 1; suffixKeep = 2; replacer = "*";
+     * 原始字符串  123456
+     * 脱敏后     1***56
+     */
+    String replacer() default "*";
+
+    /**
+     * 前缀保留长度
+     */
+    int prefixKeep() default 0;
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/BankCardDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 银行卡号
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@SliderDesensitize(prefixKeep = 6, suffixKeep = 2, replacer = "*") // 银行卡号;比如:9988002866797031脱敏之后为998800********31
+public @interface BankCardDesensitize {
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/CarLicenseDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 车牌号
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@SliderDesensitize(prefixKeep = 3, suffixKeep = 1, replacer = "*") // 车牌号;比如:粤A66666脱敏之后为粤A6***6
+public @interface CarLicenseDesensitize {
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/ChineseNameDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 中文名
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@SliderDesensitize(prefixKeep = 1, suffixKeep = 0, replacer = "*") // 中文名;比如:刘子豪脱敏之后为刘**
+public @interface ChineseNameDesensitize {
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/EmailDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.RegexDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 邮箱
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@RegexDesensitize(regex = "(^.)[^@]*(@.*$)", replacer ="$1****$2")  // 邮箱;比如:example@gmail.com脱敏之后为e****@gmail.com
+public @interface EmailDesensitize {
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/FixedPhoneDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 固定电话
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@SliderDesensitize(prefixKeep = 4, suffixKeep = 2, replacer = "*") // 固定电话;比如:01086551122脱敏之后为0108*****22
+public @interface FixedPhoneDesensitize {
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/IdCardDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 身份证
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@SliderDesensitize(prefixKeep = 6, suffixKeep = 2, replacer = "*") // 身份证号码;比如:530321199204074611脱敏之后为530321**********11
+public @interface IdCardDesensitize {
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/PasswordDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 密码
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@SliderDesensitize(prefixKeep = 0, suffixKeep = 0, replacer = "*") // 密码;比如:123456脱敏之后为******
+public @interface PasswordDesensitize {
+}

+ 21 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/annotation/constraints/PhoneNumberDesensitize.java

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.framework.desensitize.annotation.constraints;
+
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 手机号
+ */
+@Documented
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@JacksonAnnotationsInside
+@SliderDesensitize(prefixKeep = 3, suffixKeep = 4, replacer = "*") // 手机号;比如:13248765917脱敏之后为132****5917
+public @interface PhoneNumberDesensitize {
+}

+ 0 - 24
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/constants/DesensitizeConstants.java

@@ -1,24 +0,0 @@
-package cn.iocoder.yudao.framework.desensitize.constants;
-
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
-
-@NoArgsConstructor(access = AccessLevel.PRIVATE)
-public class DesensitizeConstants {
-
-    /**
-     * 默认正则
-     */
-    public static final String DEFAULT_REGEX = null;
-
-    /**
-     * 默认保持长度
-     */
-    public static final int DEFAULT_KEEP_LENGTH = -1;
-
-    /**
-     * 默认替换字符
-     */
-    public static final String DEFAULT_REPLACER = "****";
-
-}

+ 0 - 49
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/enums/DesensitizationStrategyEnum.java

@@ -1,49 +0,0 @@
-package cn.iocoder.yudao.framework.desensitize.enums;
-
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
-import static cn.iocoder.yudao.framework.desensitize.constants.DesensitizeConstants.DEFAULT_KEEP_LENGTH;
-import static cn.iocoder.yudao.framework.desensitize.constants.DesensitizeConstants.DEFAULT_REGEX;
-import static cn.iocoder.yudao.framework.desensitize.constants.DesensitizeConstants.DEFAULT_REPLACER;
-
-@Getter
-@RequiredArgsConstructor
-public enum DesensitizationStrategyEnum {
-    // 常用脱敏业务
-    PHONE_NUMBER(DEFAULT_REGEX, 3, 4, DEFAULT_REPLACER), // 手机号;比如:13248765917脱敏之后为132****5917
-    FIXED_PHONE(DEFAULT_REGEX, 4, 2, DEFAULT_REPLACER), // 固定电话;比如:01086551122脱敏之后为0108*****22
-    ID_CARD(DEFAULT_REGEX, 6, 2, DEFAULT_REPLACER), // 身份证号码;比如:530321199204074611脱敏之后为530321**********11
-    BANK_CARD(DEFAULT_REGEX, 6, 2, DEFAULT_REPLACER), // 银行卡号;比如:9988002866797031脱敏之后为998800********31
-    CHINESE_NAME(DEFAULT_REGEX, 1, 0, "**"),// 中文名;比如:刘子豪脱敏之后为刘**
-    ADDRESS("[\\s\\S]+区", DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER), // 地址只显示到地区,不显示详细地址;比如:广州市天河区幸福小区102号脱敏之后为广州市天河区********
-    EMAIL("(^.)[^@]*(@.*$)", DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, "$1****$2"), // 邮箱;比如:example@gmail.com脱敏之后为e******@gmail.com
-    CAR_LICENSE(DEFAULT_REGEX, 3, 1, DEFAULT_REPLACER), // 车牌号;比如:粤A66666脱敏之后为粤A6***6
-    PASSWORD(DEFAULT_REGEX, 0, 0, DEFAULT_REPLACER), // 密码;比如:123456脱敏之后为******
-
-    // 自定义脱敏业务
-    REGEX(DEFAULT_REGEX, DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER), // 自定义正则表达式
-    SLIDE(DEFAULT_REGEX, DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER), // 滑动脱敏
-    CUSTOM_HANDLE(DEFAULT_REGEX, DEFAULT_KEEP_LENGTH, DEFAULT_KEEP_LENGTH, DEFAULT_REPLACER); // 自定义处理器
-    ;
-
-    /**
-     * 正则表达式
-     */
-    private final String regex;
-
-    /**
-     * 前缀保留长度
-     */
-    private final int preKeep;
-
-    /**
-     * 后缀保留长度
-     */
-    private final int suffixKeep;
-
-    /**
-     * 脱敏替换字符
-     */
-    private final String replacer;
-}

+ 0 - 10
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/DefaultDesensitizationHandler.java

@@ -1,10 +0,0 @@
-package cn.iocoder.yudao.framework.desensitize.handler;
-
-public class DefaultDesensitizationHandler implements DesensitizationHandler {
-
-    @Override
-    public String handle(String origin) {
-        return origin;
-    }
-
-}

+ 1 - 1
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/DesensitizationHandler.java

@@ -8,6 +8,6 @@ public interface DesensitizationHandler {
      * @param origin 原始字符串
      * @return 脱敏后的字符串
      */
-    String handle(String origin);
+    String desensitize(String origin, Object... arg);
 
 }

+ 34 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/DesensitizationHandlerHolder.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.framework.desensitize.handler;
+
+import cn.hutool.core.util.ReflectUtil;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class DesensitizationHandlerHolder {
+    /**
+     * handler 缓存,默认初始化内置的处理器
+     */
+    private static final Map<Class<? extends DesensitizationHandler>, DesensitizationHandler> HANDLER_MAP = new ConcurrentHashMap<>() {{
+        put(RegexDesensitizationHandler.class, new RegexDesensitizationHandler());
+        put(SliderDesensitizationHandler.class, new SliderDesensitizationHandler());
+    }};
+
+    public static DesensitizationHandler getDesensitizationHandler(Class<? extends DesensitizationHandler> clazz) {
+        DesensitizationHandler handler = HANDLER_MAP.get(clazz);
+        if (handler != null) {
+            return handler;
+        }
+        synchronized (DesensitizationHandlerHolder.class) {
+            handler = HANDLER_MAP.get(clazz);
+            // 双重校验锁
+            if (handler != null) {
+                return handler;
+            }
+            handler = ReflectUtil.newInstanceIfPossible(clazz);
+            HANDLER_MAP.put(clazz, handler);
+        }
+        return handler;
+    }
+
+}

+ 13 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/RegexDesensitizationHandler.java

@@ -0,0 +1,13 @@
+package cn.iocoder.yudao.framework.desensitize.handler;
+
+public class RegexDesensitizationHandler implements DesensitizationHandler {
+
+    @Override
+    public String desensitize(String origin, Object... arg) {
+        String regex = (String) arg[0];
+        String replacer = (String) arg[1];
+
+        return origin.replaceAll(regex, replacer);
+    }
+
+}

+ 39 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/handler/SliderDesensitizationHandler.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.desensitize.handler;
+
+public class SliderDesensitizationHandler implements DesensitizationHandler {
+
+    @Override
+    public String desensitize(String origin, Object... arg) {
+        int prefixKeep = (Integer) arg[0];
+        int suffixKeep = (Integer) arg[1];
+        String replacer = (String) arg[2];
+
+        int length = origin.length();
+
+        // 原始字符串长度小于等于保留长度,则原始字符串全部替换
+        if (prefixKeep >= length || suffixKeep >= length) {
+            return buildReplacerByLength(replacer, length);
+        }
+
+        // 如果原始字符串小于等于前后缀保留字符串长度,则原始字符串全部替换
+        if ((prefixKeep + suffixKeep) >= length) {
+            return buildReplacerByLength(replacer, length);
+        }
+
+        int interval = length - prefixKeep - suffixKeep;
+        return origin.substring(0, prefixKeep) +
+                buildReplacerByLength(replacer, interval) +
+                origin.substring(prefixKeep + interval);
+    }
+
+    /**
+     * 根据长度循环构建替换符
+     *
+     * @param replacer 替换符
+     * @param length   长度
+     * @return 构建后的替换符
+     */
+    private String buildReplacerByLength(String replacer, int length) {
+        return String.valueOf(replacer).repeat(Math.max(0, length));
+    }
+}

+ 76 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/main/java/cn/iocoder/yudao/framework/desensitize/serializer/StringDesensitizeSerializer.java

@@ -0,0 +1,76 @@
+package cn.iocoder.yudao.framework.desensitize.serializer;
+
+import cn.hutool.core.util.ReflectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.desensitize.annotation.Desensitize;
+import cn.iocoder.yudao.framework.desensitize.annotation.RegexDesensitize;
+import cn.iocoder.yudao.framework.desensitize.annotation.SliderDesensitize;
+import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandler;
+import cn.iocoder.yudao.framework.desensitize.handler.DesensitizationHandlerHolder;
+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.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+/**
+ * 脱敏序列化器
+ */
+public class StringDesensitizeSerializer extends StdSerializer<String> implements ContextualSerializer {
+    private final DesensitizationHandler desensitizationHandler;
+
+    protected StringDesensitizeSerializer(DesensitizationHandler desensitizationHandler) {
+        super(String.class);
+        this.desensitizationHandler = desensitizationHandler;
+    }
+
+
+    @Override
+    public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException {
+        Desensitize annotation = beanProperty.getAnnotation(Desensitize.class);
+        if (annotation == null) {
+            return this;
+        }
+
+        return new StringDesensitizeSerializer(DesensitizationHandlerHolder.getDesensitizationHandler(annotation.desensitizationHandler()));
+    }
+
+    @Override
+    public void serialize(String value, JsonGenerator gen, SerializerProvider serializerProvider) throws IOException {
+        if (StrUtil.isBlank(value)) {
+            gen.writeNull();
+            return;
+        }
+
+        String currentName = gen.getOutputContext().getCurrentName();
+        Object currentValue = gen.getCurrentValue();
+        Class<?> currentValueClass = currentValue.getClass();
+        Field field = ReflectUtil.getField(currentValueClass, currentName);
+
+        // 滑动处理器
+        SliderDesensitize sliderDesensitize = field.getAnnotation(SliderDesensitize.class);
+        if (sliderDesensitize != null) {
+            value = this.desensitizationHandler.desensitize(value, sliderDesensitize.prefixKeep(), sliderDesensitize.suffixKeep(), sliderDesensitize.replacer());
+        }
+
+        // 正则处理器
+        RegexDesensitize regexDesensitize = field.getAnnotation(RegexDesensitize.class);
+        if (regexDesensitize != null) {
+            value = this.desensitizationHandler.desensitize(value, regexDesensitize.regex(), regexDesensitize.replacer());
+        }
+
+        // 自定义处理器
+        Desensitize desensitize = field.getAnnotation(Desensitize.class);
+        if (desensitize != null) {
+            value = this.desensitizationHandler.desensitize(value);
+        }
+
+        gen.writeString(value);
+    }
+
+}

+ 25 - 0
yudao-framework/yudao-spring-boot-starter-biz-desensitize/src/test/java/cn/iocoder/yudao/framework/desensitize/handler/DesensitizationHandlerTest.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.framework.desensitize.handler;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class DesensitizationHandlerTest {
+
+    @Test
+    public void testSliderDesensitizationHandler() {
+        DesensitizationHandler handler = DesensitizationHandlerHolder.getDesensitizationHandler(SliderDesensitizationHandler.class);
+
+        Assertions.assertEquals("A****FG", handler.desensitize("ABCDEFG", 1, 2, "*"));
+        Assertions.assertEquals("芋**码", handler.desensitize("芋道源码", 1, 1, "*"));
+        Assertions.assertEquals("****", handler.desensitize("芋道源码", 4, 0, "*"));
+    }
+
+    @Test
+    public void testRegexDesensitizationHandler() {
+        DesensitizationHandler handler = DesensitizationHandlerHolder.getDesensitizationHandler(RegexDesensitizationHandler.class);
+
+        Assertions.assertEquals("e****@gmail.com", handler.desensitize("example@gmail.com", "(^.)[^@]*(@.*$)", "$1****$2"));
+        Assertions.assertEquals("***,铁***", handler.desensitize("他妈的,铁废物", "他妈的|去你大爷|卧槽|草泥马|废物", "***"));
+    }
+
+}