14 changed files with 250 additions and 3 deletions
@ -0,0 +1,44 @@ |
|||
package com.epmet.commons.tools.annotation; |
|||
|
|||
import com.epmet.commons.tools.enums.RequirePermissionEnum; |
|||
import javassist.runtime.Inner; |
|||
|
|||
import java.lang.annotation.*; |
|||
import java.util.function.Function; |
|||
|
|||
/** |
|||
* 标记一个接口,它的返回值中的某些字段需要打掩码 |
|||
*/ |
|||
@Target(ElementType.METHOD) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
public @interface MaskResponse { |
|||
|
|||
/** |
|||
* 掩码类型 |
|||
*/ |
|||
String MASK_TYPE_ID_CARD = "ID_CARD"; |
|||
String MASK_TYPE_MOBILE = "MOBILE"; |
|||
|
|||
///**
|
|||
// * 默认的一些字段,如果没有手动指定,就会使用默认的。如果手动指定了,就不再使用默认的
|
|||
// */
|
|||
//String[] defaultFieldnames = {"idCard","mobile","phone"};
|
|||
//
|
|||
///**
|
|||
// * 默认字段对应的掩码类型
|
|||
// */
|
|||
//String[] defaultFieldsMaskType = { MASK_TYPE_ID_CARD, MASK_TYPE_MOBILE, MASK_TYPE_MOBILE };
|
|||
|
|||
/** |
|||
* 要打码的字段列表。会递归的着这些字段 |
|||
* @return |
|||
*/ |
|||
String[] fieldNames() default {"idCard","mobile","phone"}; |
|||
|
|||
/** |
|||
* 要打码的类型 |
|||
* @return |
|||
*/ |
|||
String[] fieldsMaskType() default { MASK_TYPE_ID_CARD, MASK_TYPE_MOBILE, MASK_TYPE_MOBILE }; |
|||
} |
@ -0,0 +1,36 @@ |
|||
package com.epmet.commons.tools.aspect; |
|||
|
|||
import com.epmet.commons.tools.annotation.MaskResponse; |
|||
import com.epmet.commons.tools.exception.EpmetErrorCode; |
|||
import com.epmet.commons.tools.exception.EpmetException; |
|||
import com.epmet.commons.tools.processor.MaskProcessor; |
|||
import com.epmet.commons.tools.utils.Result; |
|||
import org.aspectj.lang.JoinPoint; |
|||
import org.aspectj.lang.annotation.AfterReturning; |
|||
import org.aspectj.lang.annotation.Aspect; |
|||
import org.aspectj.lang.reflect.MethodSignature; |
|||
import org.springframework.core.annotation.Order; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Aspect |
|||
@Component |
|||
@Order(0) |
|||
public class MaskResponseAspect { |
|||
|
|||
@AfterReturning(pointcut = "@annotation(com.epmet.commons.tools.annotation.MaskResponse)", returning = "result") |
|||
public Object proceed(JoinPoint point, Result result) throws Throwable { |
|||
MethodSignature signature = (MethodSignature) point.getSignature(); |
|||
MaskResponse maskResponseAnno = signature.getMethod().getAnnotation(MaskResponse.class); |
|||
|
|||
String[] fieldNames = maskResponseAnno.fieldNames(); |
|||
String[] fieldsMaskType = maskResponseAnno.fieldsMaskType(); |
|||
|
|||
if (fieldNames.length != fieldsMaskType.length) { |
|||
String msg = "掩码配置错误"; |
|||
throw new EpmetException(EpmetErrorCode.SERVER_ERROR.getCode(), msg, msg); |
|||
} |
|||
|
|||
new MaskProcessor(fieldNames, fieldsMaskType).mask(result); |
|||
return null; |
|||
} |
|||
} |
@ -0,0 +1,142 @@ |
|||
package com.epmet.commons.tools.processor; |
|||
|
|||
import cn.hutool.core.util.StrUtil; |
|||
import com.epmet.commons.tools.annotation.MaskResponse; |
|||
import com.epmet.commons.tools.exception.ExceptionUtils; |
|||
import com.epmet.commons.tools.page.PageData; |
|||
import com.epmet.commons.tools.utils.Result; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
|
|||
import java.lang.reflect.Field; |
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.regex.Pattern; |
|||
|
|||
@Slf4j |
|||
public class MaskProcessor { |
|||
|
|||
|
|||
public static final String EPMET_PACKAGE_PREFIX = "com.epmet"; |
|||
|
|||
private List<String> fieldNames; |
|||
private List<String> fieldsMaskType; |
|||
|
|||
public MaskProcessor(String[] fields, String[] fieldsMaskType) { |
|||
if (fields != null && fields.length > 0) { |
|||
this.fieldNames = Arrays.asList(fields); |
|||
this.fieldsMaskType = Arrays.asList(fieldsMaskType); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 为dto中的属性打掩码 |
|||
* @param object |
|||
*/ |
|||
public void mask(Object object) { |
|||
if (object == null) { |
|||
return; |
|||
} |
|||
|
|||
if (object instanceof Result) { |
|||
mask(((Result<?>) object).getData()); |
|||
return; |
|||
} else if (object instanceof PageData) { |
|||
mask(((PageData<?>) object).getList()); |
|||
return; |
|||
} else if (object instanceof List) { |
|||
((List)object).forEach(e -> mask(e)); |
|||
return; |
|||
} else if (object instanceof Map) { |
|||
((Map) object).values().forEach(v -> mask(v)); |
|||
return; |
|||
} else if (object.getClass().getName().startsWith(EPMET_PACKAGE_PREFIX)) { |
|||
// 自定义bean,走反射
|
|||
maskEpmetBean(object); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 反射 |
|||
* @param object |
|||
*/ |
|||
private void maskEpmetBean(Object object) { |
|||
Field[] declaredFields = object.getClass().getDeclaredFields(); |
|||
for (Field currentField : declaredFields) { |
|||
currentField.setAccessible(true); |
|||
try { |
|||
String fieldName = currentField.getName(); |
|||
Object value = currentField.get(object); |
|||
// 是epmet的类,继续下钻
|
|||
if (currentField.getClass().getName().startsWith(EPMET_PACKAGE_PREFIX)) { |
|||
maskEpmetBean(value); |
|||
continue; |
|||
} |
|||
|
|||
// 是字符串
|
|||
String fieldValue; |
|||
if (value instanceof String && StringUtils.isNotBlank(fieldValue = (String) value)) { |
|||
int fieldIndexInAnnoAttrs = fieldNames.indexOf(fieldName); |
|||
if (fieldIndexInAnnoAttrs != -1) { |
|||
String product = maskString(fieldValue, fieldsMaskType.get(fieldIndexInAnnoAttrs)); |
|||
currentField.set(object, product); |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
// 非字符串,非epmet类的其他类型
|
|||
mask(value); |
|||
} catch (IllegalAccessException e) { |
|||
log.error("【mask一些字段报错】{}", ExceptionUtils.getErrorStackTrace(e)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 把字符串变更为掩码 |
|||
* @param originString |
|||
* @return |
|||
*/ |
|||
public String maskString(String originString, String maskType) { |
|||
if (MaskResponse.MASK_TYPE_ID_CARD.equals(maskType)) { |
|||
return maskIdCard(originString); |
|||
} else if (MaskResponse.MASK_TYPE_MOBILE.equals(maskType)) { |
|||
return maskMobile(originString); |
|||
} else { |
|||
return originString; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 将明文字符串打码变为掩码。保留前6,后面打码 |
|||
* @param originString |
|||
* @return |
|||
*/ |
|||
private String maskIdCard(String originString) { |
|||
// 仅将6位之后的全都打码
|
|||
int length = originString.length(); |
|||
if (length <= 6) { |
|||
return originString; |
|||
} |
|||
|
|||
return originString.replace(originString.substring(6), StrUtil.repeatByLength("*", length - 6)); |
|||
} |
|||
|
|||
/** |
|||
* 将明文字符串打码变为掩码。保留前3后4,中间打码 |
|||
* 187****3461 |
|||
* @param originString |
|||
* @return |
|||
*/ |
|||
private String maskMobile(String originString) { |
|||
int length = originString.length(); |
|||
if (length <= 7) { |
|||
return originString; |
|||
} |
|||
|
|||
String maskStr = StrUtil.repeatByLength("*", length - 7); |
|||
|
|||
return originString.replaceAll("^(1\\d{2})\\d*(\\d{4})$", new StringBuilder("$1").append(maskStr).append("$2").toString()); |
|||
} |
|||
} |
Loading…
Reference in new issue