org.aoju.bus.sensitive.Provider Maven / Gradle / Ivy
/*********************************************************************************
* *
* The MIT License (MIT) *
* *
* Copyright (c) 2015-2020 aoju.org and other contributors. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy *
* of this software and associated documentation files (the "Software"), to deal *
* in the Software without restriction, including without limitation the rights *
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN *
* THE SOFTWARE. *
* *
********************************************************************************/
package org.aoju.bus.sensitive;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.serializer.ContextValueFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.aoju.bus.core.lang.Symbol;
import org.aoju.bus.core.lang.exception.InstrumentException;
import org.aoju.bus.core.toolkit.*;
import org.aoju.bus.sensitive.annotation.Condition;
import org.aoju.bus.sensitive.annotation.*;
import org.aoju.bus.sensitive.provider.ConditionProvider;
import org.aoju.bus.sensitive.provider.StrategyProvider;
import org.aoju.bus.sensitive.strategy.BuiltInStrategy;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.*;
/**
* 脱敏接口
*
* @param 参数类型
* @author Kimi Liu
* @version 6.1.3
* @since JDK 1.8+
*/
public class Provider {
/**
* 脱敏属性
*/
private String[] value;
/**
* 深度复制
* 1. 为了避免深拷贝要求用户实现 clone 和 序列化的相关接口
* 2. 为了避免使用 dozer 这种比较重的工具
* 3. 自己实现暂时工作量比较大
*
* 暂时使用 fastJson 作为实现深度拷贝的方式
*
* @param object 对象
* @param 泛型
* @return 深拷贝后的对象
*/
public static T clone(T object) {
final Class clazz = object.getClass();
String jsonString = JSON.toJSONString(object);
return (T) JSON.parseObject(jsonString, clazz);
}
/**
* 是否已经是脱敏过的内容了
*
* @param object 原始数据
* @return 是否已经脱敏了
*/
public static boolean alreadyBeSentisived(Object object) {
return object == null || object.toString().indexOf(Symbol.STAR) > 0;
}
/**
* 将json字符串转化为StringObject类型的map
*
* @param jsonStr json字符串
* @return map
*/
public static Map parseToObjectMap(String jsonStr) {
return JSON.parseObject(jsonStr, new TypeReference>() {
});
}
/**
* 将map转化为json字符串
*
* @param params 参数集合
* @return json
*/
public static String parseMaptoJSONString(Map params) {
return JSON.toJSONString(params, SerializerFeature.WriteMapNullValue);
}
/**
* 对象进行脱敏操作
* 原始对象不变,返回脱敏后的新对象
* 1. 为什么这么设计?
* 不能因为脱敏,就导致代码中的对象被改变 否则代码逻辑会出现问题
*
* @param object 原始对象
* @param annotation 注解信息
* @param clone 是否克隆
* @return 脱敏后的新对象
*/
public T on(T object, Annotation annotation, boolean clone) {
if (ObjectKit.isEmpty(object)) {
return object;
}
if (ObjectKit.isNotEmpty(annotation)) {
Sensitive sensitive = (Sensitive) annotation;
this.value = sensitive.field();
}
// 1. 初始化
final Class clazz = object.getClass();
final Context context = new Context();
if (clone) {
// 2. 深度复制,不改变原始对象
T copy = clone(object);
handleClassField(context, copy, clazz);
return copy;
}
// 3. 脱敏处理
handleClassField(context, object, clazz);
return object;
}
/**
* 返回脱敏后的 json
* 1. 避免 desCopy 造成的对象新建的性能浪费
*
* @param object 对象
* @param annotation 注解
* @return json
*/
public String json(T object, Annotation annotation) {
if (ObjectKit.isEmpty(object)) {
return JSON.toJSONString(object);
}
if (ObjectKit.isNotEmpty(annotation)) {
Sensitive sensitive = (Sensitive) annotation;
this.value = sensitive.field();
}
final Context context = new Context();
ContextValueFilter filter = new Filter(context);
return JSON.toJSONString(object, filter);
}
/**
* 处理脱敏相关信息
*
* @param context 执行上下文
* @param copyObject 拷贝的新对象
* @param clazz class 类型
*/
private void handleClassField(final Context context,
final Object copyObject,
final Class clazz) {
// 每一个实体对应的字段,只对当前 clazz 生效
List fieldList = ClassKit.getAllFieldList(clazz);
context.setAllFieldList(fieldList);
context.setCurrentObject(copyObject);
try {
for (Field field : fieldList) {
if (ArrayKit.isNotEmpty(this.value)) {
if (!Arrays.asList(this.value).contains(field.getName())) {
continue;
}
}
// 设置当前处理的字段
final Class fieldTypeClass = field.getType();
context.setCurrentField(field);
// 处理 @Entry 注解
Entry sensitiveEntry = field.getAnnotation(Entry.class);
if (ObjectKit.isNotNull(sensitiveEntry)) {
if (TypeKit.isJavaBean(fieldTypeClass)) {
// 为普通 javabean 对象
final Object fieldNewObject = field.get(copyObject);
handleClassField(context, fieldNewObject, fieldTypeClass);
} else if (TypeKit.isArray(fieldTypeClass)) {
// 为数组类型
Object[] arrays = (Object[]) field.get(copyObject);
if (ArrayKit.isNotEmpty(arrays)) {
Object firstArrayEntry = arrays[0];
final Class entryFieldClass = firstArrayEntry.getClass();
//1. 如果需要特殊处理,则循环特殊处理
if (needHandleEntryType(entryFieldClass)) {
for (Object arrayEntry : arrays) {
handleClassField(context, arrayEntry, entryFieldClass);
}
} else {
//2, 基础值,直接循环设置即可
final int arrayLength = arrays.length;
Object newArray = Array.newInstance(entryFieldClass, arrayLength);
for (int i = 0; i < arrayLength; i++) {
Object entry = arrays[i];
Object result = handleSensitiveEntry(context, entry, field);
Array.set(newArray, i, result);
}
field.set(copyObject, newArray);
}
}
} else if (TypeKit.isCollection(fieldTypeClass)) {
// Collection 接口的子类
final Collection