【优化】数据脱敏支持 Spring el 表达式,支持根据权限控制脱敏

This commit is contained in:
YunaiV 2024-08-03 19:13:11 +08:00
parent 1285a90c5d
commit a042a4c366
23 changed files with 164 additions and 55 deletions

View File

@ -3,11 +3,15 @@ package cn.iocoder.yudao.framework.common.util.spring;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser; import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
@ -86,4 +90,20 @@ public class SpringExpressionUtils {
return result; return result;
} }
/**
* Bean 工厂解析 EL 表达式的结果
*
* @param expressionString EL 表达式
* @return 执行界面
*/
public static Object parseExpression(String expressionString) {
if (StrUtil.isBlank(expressionString)) {
return null;
}
Expression expression = EXPRESSION_PARSER.parseExpression(expressionString);
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getApplicationContext()));
return expression.getValue(context);
}
} }

View File

@ -5,11 +5,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.serializer.StringDesensi
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 顶级脱敏注解自定义注解需要使用此注解 * 顶级脱敏注解自定义注解需要使用此注解

View File

@ -1,5 +1,7 @@
package cn.iocoder.yudao.framework.desensitize.core.base.handler; package cn.iocoder.yudao.framework.desensitize.core.base.handler;
import cn.hutool.core.util.ReflectUtil;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
/** /**
@ -18,4 +20,21 @@ public interface DesensitizationHandler<T extends Annotation> {
*/ */
String desensitize(String origin, T annotation); String desensitize(String origin, T annotation);
/**
* 是否禁用脱敏的 Spring EL 表达式
*
* 如果返回 true 则跳过脱敏
*
* @param annotation 注解信息
* @return 是否禁用脱敏的 Spring EL 表达式
*/
default String getDisable(T annotation) {
// 约定默认就是 enable() 属性如果不符合子类重写
try {
return (String) ReflectUtil.invoke(annotation, "disable");
} catch (Exception ex) {
return "";
}
}
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.regex.handler.EmailDesensitizationHandler; import cn.iocoder.yudao.framework.desensitize.core.regex.handler.EmailDesensitizationHandler;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 邮箱脱敏注解 * 邮箱脱敏注解
@ -33,4 +29,12 @@ public @interface EmailDesensitize {
* 比如example@gmail.com 脱敏之后为 e****@gmail.com * 比如example@gmail.com 脱敏之后为 e****@gmail.com
*/ */
String replacer() default "$1****$2"; String replacer() default "$1****$2";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.regex.handler.DefaultRegexDesensitizationHandler; import cn.iocoder.yudao.framework.desensitize.core.regex.handler.DefaultRegexDesensitizationHandler;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 正则脱敏注解 * 正则脱敏注解
@ -35,4 +31,12 @@ public @interface RegexDesensitize {
* 脱敏后字符串 ******456789 * 脱敏后字符串 ******456789
*/ */
String replacer() default "******"; String replacer() default "******";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.desensitize.core.regex.handler; package cn.iocoder.yudao.framework.desensitize.core.regex.handler;
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
@ -14,6 +15,13 @@ public abstract class AbstractRegexDesensitizationHandler<T extends Annotation>
@Override @Override
public String desensitize(String origin, T annotation) { public String desensitize(String origin, T annotation) {
// 1. 判断是否禁用脱敏
Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation));
if (Boolean.TRUE.equals(disable)) {
return origin;
}
// 2. 执行脱敏
String regex = getRegex(annotation); String regex = getRegex(annotation);
String replacer = getReplacer(annotation); String replacer = getReplacer(annotation);
return origin.replaceAll(regex, replacer); return origin.replaceAll(regex, replacer);

View File

@ -18,4 +18,10 @@ public class DefaultRegexDesensitizationHandler extends AbstractRegexDesensitiza
String getReplacer(RegexDesensitize annotation) { String getReplacer(RegexDesensitize annotation) {
return annotation.replacer(); return annotation.replacer();
} }
@Override
public String getDisable(RegexDesensitize annotation) {
return annotation.disable();
}
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.BankCardDesensitization; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.BankCardDesensitization;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 银行卡号 * 银行卡号
@ -37,4 +33,11 @@ public @interface BankCardDesensitize {
*/ */
String replacer() default "*"; String replacer() default "*";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.CarLicenseDesensitization; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.CarLicenseDesensitization;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 车牌号 * 车牌号
@ -37,4 +33,11 @@ public @interface CarLicenseDesensitize {
*/ */
String replacer() default "*"; String replacer() default "*";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.ChineseNameDesensitization; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.ChineseNameDesensitization;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 中文名 * 中文名
@ -37,4 +33,11 @@ public @interface ChineseNameDesensitize {
*/ */
String replacer() default "*"; String replacer() default "*";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.FixedPhoneDesensitization; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.FixedPhoneDesensitization;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 固定电话 * 固定电话
@ -37,4 +33,11 @@ public @interface FixedPhoneDesensitize {
*/ */
String replacer() default "*"; String replacer() default "*";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.IdCardDesensitization; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.IdCardDesensitization;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 身份证 * 身份证
@ -37,4 +33,11 @@ public @interface IdCardDesensitize {
*/ */
String replacer() default "*"; String replacer() default "*";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.MobileDesensitization; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.MobileDesensitization;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 手机号 * 手机号
@ -37,4 +33,11 @@ public @interface MobileDesensitize {
*/ */
String replacer() default "*"; String replacer() default "*";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.PasswordDesensitization; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.PasswordDesensitization;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 密码 * 密码
@ -39,4 +35,11 @@ public @interface PasswordDesensitize {
*/ */
String replacer() default "*"; String replacer() default "*";
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -4,11 +4,7 @@ import cn.iocoder.yudao.framework.desensitize.core.base.annotation.DesensitizeBy
import cn.iocoder.yudao.framework.desensitize.core.slider.handler.DefaultDesensitizationHandler; import cn.iocoder.yudao.framework.desensitize.core.slider.handler.DefaultDesensitizationHandler;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import java.lang.annotation.Documented; import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** /**
* 滑动脱敏注解 * 滑动脱敏注解
@ -40,4 +36,12 @@ public @interface SliderDesensitize {
* 前缀保留长度 * 前缀保留长度
*/ */
int prefixKeep() default 0; int prefixKeep() default 0;
/**
* 是否禁用脱敏
*
* 支持 Spring EL 表达式如果返回 true 则跳过脱敏
*/
String disable() default "";
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.desensitize.core.slider.handler; package cn.iocoder.yudao.framework.desensitize.core.slider.handler;
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler; import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
@ -14,6 +15,13 @@ public abstract class AbstractSliderDesensitizationHandler<T extends Annotation>
@Override @Override
public String desensitize(String origin, T annotation) { public String desensitize(String origin, T annotation) {
// 1. 判断是否禁用脱敏
Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation));
if (Boolean.FALSE.equals(disable)) {
return origin;
}
// 2. 执行脱敏
int prefixKeep = getPrefixKeep(annotation); int prefixKeep = getPrefixKeep(annotation);
int suffixKeep = getSuffixKeep(annotation); int suffixKeep = getSuffixKeep(annotation);
String replacer = getReplacer(annotation); String replacer = getReplacer(annotation);

View File

@ -24,4 +24,9 @@ public class BankCardDesensitization extends AbstractSliderDesensitizationHandle
return annotation.replacer(); return annotation.replacer();
} }
@Override
public String getDisable(BankCardDesensitize annotation) {
return "";
}
} }

View File

@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.CarLicenseD
* @author gaibu * @author gaibu
*/ */
public class CarLicenseDesensitization extends AbstractSliderDesensitizationHandler<CarLicenseDesensitize> { public class CarLicenseDesensitization extends AbstractSliderDesensitizationHandler<CarLicenseDesensitize> {
@Override @Override
Integer getPrefixKeep(CarLicenseDesensitize annotation) { Integer getPrefixKeep(CarLicenseDesensitize annotation) {
return annotation.prefixKeep(); return annotation.prefixKeep();
@ -22,4 +23,10 @@ public class CarLicenseDesensitization extends AbstractSliderDesensitizationHand
String getReplacer(CarLicenseDesensitize annotation) { String getReplacer(CarLicenseDesensitize annotation) {
return annotation.replacer(); return annotation.replacer();
} }
@Override
public String getDisable(CarLicenseDesensitize annotation) {
return annotation.disable();
}
} }

View File

@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.SliderDesen
* @author gaibu * @author gaibu
*/ */
public class DefaultDesensitizationHandler extends AbstractSliderDesensitizationHandler<SliderDesensitize> { public class DefaultDesensitizationHandler extends AbstractSliderDesensitizationHandler<SliderDesensitize> {
@Override @Override
Integer getPrefixKeep(SliderDesensitize annotation) { Integer getPrefixKeep(SliderDesensitize annotation) {
return annotation.prefixKeep(); return annotation.prefixKeep();
@ -22,4 +23,5 @@ public class DefaultDesensitizationHandler extends AbstractSliderDesensitization
String getReplacer(SliderDesensitize annotation) { String getReplacer(SliderDesensitize annotation) {
return annotation.replacer(); return annotation.replacer();
} }
} }

View File

@ -8,6 +8,7 @@ import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.FixedPhoneD
* @author gaibu * @author gaibu
*/ */
public class FixedPhoneDesensitization extends AbstractSliderDesensitizationHandler<FixedPhoneDesensitize> { public class FixedPhoneDesensitization extends AbstractSliderDesensitizationHandler<FixedPhoneDesensitize> {
@Override @Override
Integer getPrefixKeep(FixedPhoneDesensitize annotation) { Integer getPrefixKeep(FixedPhoneDesensitize annotation) {
return annotation.prefixKeep(); return annotation.prefixKeep();
@ -22,4 +23,5 @@ public class FixedPhoneDesensitization extends AbstractSliderDesensitizationHand
String getReplacer(FixedPhoneDesensitize annotation) { String getReplacer(FixedPhoneDesensitize annotation) {
return annotation.replacer(); return annotation.replacer();
} }
} }

View File

@ -22,4 +22,5 @@ public class IdCardDesensitization extends AbstractSliderDesensitizationHandler<
String getReplacer(IdCardDesensitize annotation) { String getReplacer(IdCardDesensitize annotation) {
return annotation.replacer(); return annotation.replacer();
} }
} }

View File

@ -23,4 +23,5 @@ public class MobileDesensitization extends AbstractSliderDesensitizationHandler<
String getReplacer(MobileDesensitize annotation) { String getReplacer(MobileDesensitize annotation) {
return annotation.replacer(); return annotation.replacer();
} }
} }

View File

@ -22,4 +22,5 @@ public class PasswordDesensitization extends AbstractSliderDesensitizationHandle
String getReplacer(PasswordDesensitize annotation) { String getReplacer(PasswordDesensitize annotation) {
return annotation.replacer(); return annotation.replacer();
} }
} }