簡単な紹介
インターネット時代の普及に伴い、ユーザー情報の重要性はますます高まっています。また、ソフトウェア開発の過程でユーザー情報の感度を下げて暗号化する必要があります。より複雑なタスクについては、注釈の感度を下げる方法を個人的に説明してください。感度低下または暗号化されたリターンを実現するためのaop統合インターセプト。
コードの説明
脱感作列挙クラス
列挙型クラスを定義し、すべての感度低下や暗号化などを処理しますが、拡張可能です。ここでは、サンプルを書き込むための注釈付きの呼び出しメソッドを示します。DesensitivezationEnum他の感度低下または暗号化方法が必要な場合は、次の列挙型を追加するだけで済みます。
package com.lgh.common.sensitive;
import com.lgh.common.utils.MaskUtils;
import java.lang.reflect.Method;
/**
* 若需要新定义一个扫描规则,这里添加即可
*
* @author lgh
* @version 1.0
* @date 2021/1/17
*/
public enum DesensitizationEnum {
// 执行类和脱敏方法名
PHONE(MaskUtils.class, "maskPhone", new Class[]{
String.class});
private Class<?> clazz;
private Method method;
DesensitizationEnum(Class<?> target, String method, Class[] paramTypes) {
this.clazz = target;
try {
this.method = target.getDeclaredMethod(method, paramTypes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public Method getMethod() {
return method;
}
}
脱感作ツール
package com.lgh.common.utils;
import org.springframework.util.StringUtils;
/**
* @author lgh
* @version 1.0
* @date 2021/1/17
*/
public class MaskUtils {
public static String maskPhone(String phone){
if(StringUtils.isEmpty(phone) || phone.length() < 8){
return phone;
}
return phone.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
}
}
アノテーションクラスの記述
このクラスは、感度低下を実現するために感度低下が必要なクラス属性に追加できます。具体的には、アノテーションを再帰的にトラバースし、反射メカニズムによって感度低下機能を実現します。
package com.lgh.common.sensitive;
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;
/**
* 参数定义注解类
* @author linguohu
* @version 1.0
* @date 2021/1/17
**/
@Target({
ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SensitiveValid {
DesensitizationEnum type();
}
脱感作ツール
特別なステートメント、再帰すると、それはインデックス再帰であり、無限ループが発生します。たとえば、オブジェクトはオブジェクトを参照し、循環アドレスが参照されるため、無限ループが発生します。再帰には10レベルあります。 。一般的に、このような深いオブジェクトは許可されません。セットアップします。
package com.lgh.common.utils;
import com.lgh.common.sensitive.DesensitizationEnum;
import com.lgh.common.sensitive.SensitiveValid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
/**
* 对象脱敏工具
*
* @author lgh
* @version 1.0
* @date 2021/1/17
*/
public class DesensitizationUtils {
private static final Logger log = LoggerFactory.getLogger(DesensitizationUtils.class);
private DesensitizationUtils() {
}
/**
* 扫描对象注解,脱敏,最高层次8层
*
* @param obj
*/
public static void format(Object obj) {
DesensitizationUtils.formatMethod(obj, 10);
}
/**
* 递归遍历数据,因为可能有对象地址应用导致循环问题,同时设置莫名奇妙的异常,所以设置递归层次,一般不要超过10层
*
* @param obj 需要反射对象
* @param level 递归层次,必须输入
*/
private static void formatMethod(Object obj, int level) {
if (obj == null || isPrimitive(obj.getClass()) || level <= 0) {
return;
}
if (obj.getClass().isArray()) {
for (Object object : (Object[]) obj) {
formatMethod(object, level--);
}
} else if (Collection.class.isAssignableFrom(obj.getClass())) {
for (Object o : ((Collection) obj)) {
formatMethod(o, level--);
}
} else if (Map.class.isAssignableFrom(obj.getClass())) {
for (Object o : ((Map) obj).values()) {
formatMethod(o, level--);
}
} else {
objFormat(obj, level);
}
}
/**
* 只有对象才格式化数据
*
* @param obj
* @param level
*/
private static void objFormat(Object obj, int level) {
for (Field field : obj.getClass().getDeclaredFields()) {
try {
if (isPrimitive(field.getType())) {
SensitiveValid sensitiveValid = field.getAnnotation(SensitiveValid.class);
if (sensitiveValid != null) {
ReflectionUtils.makeAccessible(field);
DesensitizationEnum desensitizationEnum = sensitiveValid.type();
Object fieldV = desensitizationEnum.getMethod().invoke(null, field.get(obj));
ReflectionUtils.setField(field, obj, fieldV);
}
} else {
ReflectionUtils.makeAccessible(field);
Object fieldValue = ReflectionUtils.getField(field, obj);
if (fieldValue == null) {
continue;
}
formatMethod(fieldValue, level - 1);
}
} catch (Exception e) {
log.error("脱敏数据处理异常", e);
}
}
}
/**
* 基本数据类型和String类型判断
*
* @param clz
* @return
*/
public static boolean isPrimitive(Class<?> clz) {
try {
if (String.class.isAssignableFrom(clz) || clz.isPrimitive()) {
return true;
} else {
return ((Class) clz.getField("TYPE").get(null)).isPrimitive();
}
} catch (Exception e) {
return false;
}
}
}
脱感作AOPの実現
不要な操作を防ぐために、Aopプラガブルプログラミングなので、制御可能なクラスアノテーションEnableDesensitivezationを記述します。
package com.lgh.common.sensitive;
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;
/**
* 方法返回值拦截器,需要注解才生效
* @author lgh
* @version 1.0
* @date 2021/1/17
**/
@Target({
ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableDesensitization {
}
最後にインターセプトaopを達成する
package com.lgh.common.sensitive;
import com.lgh.common.utils.DesensitizationUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import org.aspectj.lang.annotation.Aspect;
import java.lang.reflect.Method;
/**
* @author lgh
* @version 1.0
* @date 2021/1/17
*/
@Aspect
@Configuration
public class SensitiveAspect {
public static final String ACCESS_EXECUTION = "execution(* com.lgh.controller..*.*(..))";
/**
* 注解脱敏处理
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around(ACCESS_EXECUTION)
public Object sensitiveClass(ProceedingJoinPoint joinPoint) throws Throwable {
return sensitiveFormat(joinPoint);
}
/**
* 插拔式注解统一拦截器。@{link EnableDesensitization } 和 @SensitiveValid
*
* @param joinPoint
* @return
* @throws Throwable
*/
public Object sensitiveFormat(ProceedingJoinPoint joinPoint) throws Throwable {
Object obj = joinPoint.proceed();
if (obj == null || DesensitizationUtils.isPrimitive(obj.getClass())) {
return obj;
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
EnableDesensitization desensitization = joinPoint.getTarget().getClass().getAnnotation(EnableDesensitization.class);
if (desensitization != null || method.getAnnotation(EnableDesensitization.class) != null) {
DesensitizationUtils.format(obj);
}
return obj;
}
}
実際の戦闘訓練
前の章で使用したUserDetailオブジェクトは、次のように電話フィールドを追加し、コメントを追加しました。
package com.lgh.common.authority.entity;
import com.lgh.common.sensitive.DesensitizationEnum;
import com.lgh.common.sensitive.SensitiveValid;
public class UserDetail {
private long id;
private String name;
@SensitiveValid(type = DesensitizationEnum.PHONE)
private String phone;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPhone() {
return phone;
}
}
次に、コントローラーで注釈を開始します
@GetMapping("/detail")
@EnableDesensitization
public IResult<UserDetail> getUser(@AuthenticationPrincipal UserDetail userDetail) {
return CommonResult.successData(userDetail);
}
これで、アクセス操作を実装しましょう