平時(shí)開(kāi)發(fā)的過(guò)程中經(jīng)常會(huì)遇到對(duì)一些敏感的字段進(jìn)行脫敏處理,防止信息泄漏,如:郵箱、用戶名、密碼等;做為一個(gè)優(yōu)秀的程序員我們不應(yīng)該遇到這種問(wèn)題時(shí)就做特殊處理,重復(fù)做相同的工作,所以我們應(yīng)該寫(xiě)一個(gè)基礎(chǔ)庫(kù)SDK,解決重復(fù)的問(wèn)題;
開(kāi)源SDK組件
<dependency>
<groupId>io.github.mingyang66</groupId>
<artifactId>oceansky-sensitive</artifactId>
<version>4.3.2</version>
</dependency>
新增JsonNullField注解,可將指定的字段值置為null,注解定義如下:
/**
* @Description : 自定義注解,標(biāo)注在屬性上,字段屬性值置為null
* ---------------------------------------------
* 生效規(guī)則:
* 1.非int、double、float、byte、short、long、boolean、char八種基本數(shù)據(jù)類型字段才會(huì)生效;
* 2.
* ---------------------------------------------
* @Author : Emily
* @CreateDate : Created in 2023/7/14 5:22 下午
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonNullField {
}
一、定義注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonSensitive {
}
@JsonSensitive標(biāo)注在類上,表示此類需要進(jìn)行脫敏處理;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonSimField {
/**
* 脫敏類型,見(jiàn)枚舉類型{@link SensitiveType}
*
* @return
*/
SensitiveType value() default SensitiveType.DEFAULT;
}
@JsonSimField標(biāo)注在類的String、Collection、String[]字段上,表示對(duì)這些字段值進(jìn)行脫敏處理;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonFlexField {
/**
* 要隱藏的參數(shù)key名稱
*
* @return
*/
String[] fieldKeys() default {};
/**
* 要隱藏的參數(shù)值的key名稱
*
* @return
*/
String fieldValue();
/**
* 脫敏類型,見(jiàn)枚舉類型{@link SensitiveType}
*
* @return
*/
SensitiveType[] types() default {};
}
@JsonFlexField注解標(biāo)注在復(fù)雜數(shù)據(jù)類型字段上,具體的使用方法會(huì)在后面舉例說(shuō)明;
二、實(shí)現(xiàn)對(duì)字段脫敏處理的核心實(shí)現(xiàn)類
public class DeSensitiveUtils {
public static final Logger logger = LoggerFactory.getLogger(DeSensitiveUtils.class);
/**
* @param entity 實(shí)體類|普通對(duì)象
* @return 對(duì)實(shí)體類進(jìn)行脫敏,返回原來(lái)的實(shí)體類對(duì)象
*/
public static <T> T acquire(final T entity) {
try {
if (JavaBeanUtils.isFinal(entity)) {
return entity;
}
if (entity instanceof Collection) {
for (Iterator it = ((Collection) entity).iterator(); it.hasNext(); ) {
acquire(it.next());
}
} else if (entity instanceof Map) {
for (Map.Entry<Object, Object> entry : ((Map<Object, Object>) entity).entrySet()) {
acquire(entry.getValue());
}
} else if (entity.getClass().isArray()) {
if (!entity.getClass().getComponentType().isPrimitive()) {
for (Object v : (Object[]) entity) {
acquire(v);
}
}
} else if (entity instanceof BaseResponse) {
acquire(((BaseResponse) entity).getData());
} else if (entity.getClass().isAnnotationPresent(JsonSensitive.class)) {
doSetField(entity);
}
} catch (IllegalAccessException exception) {
logger.error(PrintExceptionInfo.printErrorInfo(exception));
}
return entity;
}
/**
* @param entity 實(shí)體類對(duì)象
* @throws IllegalAccessException 非法訪問(wèn)異常
* @Description 對(duì)實(shí)體類entity的屬性及父類的屬性遍歷并對(duì)符合條件的屬性進(jìn)行多語(yǔ)言翻譯
*/
protected static <T> void doSetField(final T entity) throws IllegalAccessException {
Field[] fields = FieldUtils.getAllFields(entity.getClass());
for (Field field : fields) {
if (JavaBeanUtils.isModifierFinal(field)) {
continue;
}
field.setAccessible(true);
Object value = field.get(entity);
if (Objects.isNull(value)) {
continue;
}
if (value instanceof String) {
doGetEntityStr(field, entity, value);
} else if (value instanceof Collection) {
doGetEntityColl(field, entity, value);
} else if (value instanceof Map) {
doGetEntityMap(field, entity, value);
} else if (value.getClass().isArray()) {
doGetEntityArray(field, entity, value);
} else {
acquire(value);
}
}
doGetEntityFlex(entity);
}
/**
* @param field 實(shí)體類屬性對(duì)象
* @param entity 實(shí)體類對(duì)象
* @param value 屬性值對(duì)象
* @throws IllegalAccessException 拋出非法訪問(wèn)異常
* @Description 對(duì)字符串進(jìn)行多語(yǔ)言支持
*/
protected static <T> void doGetEntityStr(final Field field, final T entity, final Object value) throws IllegalAccessException {
if (field.isAnnotationPresent(JsonSimField.class)) {
field.set(entity, DataMaskUtils.doGetProperty((String) value, field.getAnnotation(JsonSimField.class).value()));
} else {
acquire(value);
}
}
/**
* @param field 實(shí)體類屬性對(duì)象
* @param entity 實(shí)體類對(duì)象
* @param value 屬性值對(duì)象
* @throws IllegalAccessException 拋出非法訪問(wèn)異常
* @Description 對(duì)Collection集合中存儲(chǔ)是字符串、實(shí)體對(duì)象進(jìn)行多語(yǔ)言支持
*/
protected static <T> void doGetEntityColl(final Field field, final T entity, final Object value) throws IllegalAccessException {
Collection<Object> list = null;
Collection collection = ((Collection) value);
for (Iterator it = collection.iterator(); it.hasNext(); ) {
Object v = it.next();
if (Objects.isNull(v)) {
continue;
}
if ((v instanceof String) && field.isAnnotationPresent(JsonSimField.class)) {
list = (list == null) ? Lists.newArrayList() : list;
list.add(DataMaskUtils.doGetProperty((String) v, field.getAnnotation(JsonSimField.class).value()));
} else {
acquire(v);
}
}
if (Objects.nonNull(list)) {
field.set(entity, list);
}
}
/**
* @param field 實(shí)體類屬性對(duì)象
* @param entity 實(shí)體類對(duì)象
* @param value 屬性值對(duì)象
* @throws IllegalAccessException 拋出非法訪問(wèn)異常
* @Description 對(duì)Map集合中存儲(chǔ)是字符串、實(shí)體對(duì)象進(jìn)行多語(yǔ)言支持
*/
protected static <T> void doGetEntityMap(final Field field, final T entity, final Object value) throws IllegalAccessException {
Map<Object, Object> dMap = ((Map<Object, Object>) value);
for (Map.Entry<Object, Object> entry : dMap.entrySet()) {
Object key = entry.getKey();
Object v = entry.getValue();
if (Objects.isNull(v)) {
continue;
}
if ((v instanceof String) && field.isAnnotationPresent(JsonSimField.class)) {
dMap.put(key, DataMaskUtils.doGetProperty((String) v, field.getAnnotation(JsonSimField.class).value()));
} else {
acquire(value);
}
}
}
/**
* @param field 實(shí)體類屬性對(duì)象
* @param entity 實(shí)體類對(duì)象
* @param value 屬性值對(duì)象
* @throws IllegalAccessException 拋出非法訪問(wèn)異常
* @Description 對(duì)數(shù)組中存儲(chǔ)是字符串、實(shí)體對(duì)象進(jìn)行多語(yǔ)言支持
*/
protected static <T> void doGetEntityArray(final Field field, final T entity, final Object value) throws IllegalAccessException {
if (value.getClass().getComponentType().isPrimitive()) {
return;
}
Object[] arrays = ((Object[]) value);
for (int i = 0; i < arrays.length; i++) {
Object v = arrays[i];
if (Objects.isNull(v)) {
continue;
}
if ((v instanceof String) && field.isAnnotationPresent(JsonSimField.class)) {
arrays[i] = DataMaskUtils.doGetProperty((String) v, field.getAnnotation(JsonSimField.class).value());
} else {
acquire(value);
}
}
}
/**
* @param entity 實(shí)體類對(duì)象
* @throws IllegalAccessException 拋出非法訪問(wèn)異常
*/
protected static <T> void doGetEntityFlex(final T entity) throws IllegalAccessException {
Field[] fields = FieldUtils.getFieldsWithAnnotation(entity.getClass(), JsonFlexField.class);
for (Field field : fields) {
field.setAccessible(true);
Object value = field.get(entity);
if (Objects.isNull(value)) {
continue;
}
JsonFlexField jsonFlexField = field.getAnnotation(JsonFlexField.class);
if (Objects.isNull(jsonFlexField.fieldValue())) {
return;
}
Field flexField = FieldUtils.getField(entity.getClass(), jsonFlexField.fieldValue(), true);
if (Objects.isNull(flexField)) {
return;
}
Object flexValue = flexField.get(entity);
if (Objects.isNull(flexValue) || !(flexValue instanceof String)) {
return;
}
int index = Arrays.asList(jsonFlexField.fieldKeys()).indexOf((String) value);
if (index < 0) {
return;
}
SensitiveType type;
if (index >= jsonFlexField.types().length) {
type = SensitiveType.DEFAULT;
} else {
type = jsonFlexField.types()[index];
}
flexField.set(entity, DataMaskUtils.doGetProperty((String) flexValue, type));
}
}
}
三、基于注解的脫敏SDK使用案例
- 對(duì)實(shí)體類中字段為字符串類型脫敏處理
@JsonSensitive
public class PubRequest {
@JsonSimField(SensitiveType.USERNAME)
public String username;
@JsonSimField
public String password;
}
- 對(duì)實(shí)體類中字段是List、Map<String,String>、String[]集合類型進(jìn)行脫敏處理
@JsonSensitive
public class PubRequest {
@JsonSimField
public Map<String, String> work;
@JsonSimField
public List<String> jobList;
@JsonSimField
public String[] jobs;
}
- 實(shí)體類中的字段是復(fù)雜數(shù)據(jù)類型脫敏處理
@JsonSensitive
public class JsonRequest extends Animal{
@JsonFlexField(fieldKeys = {"email", "phone"}, fieldValue = "fieldValue", types = {SensitiveType.EMAIL, SensitiveType.PHONE})
private String fieldKey;
private String fieldValue;
}
復(fù)雜數(shù)據(jù)類型其實(shí)就是fieldKey可以指定多個(gè)不同的字段名,fieldValue是具體的字段值,如果fieldKey是email時(shí)fieldValue傳遞的就是郵箱,就按照types中指定脫敏策略為郵箱的策略脫敏;
- 實(shí)體類中的屬性字段是集合類型,集合中存放的是嵌套的實(shí)體類
@JsonSensitive
public static class Job {
@JsonSimField(SensitiveType.DEFAULT)
private String work;
@JsonSimField(SensitiveType.EMAIL)
private String email;
}
嵌套實(shí)體類屬性字段
public Job job;
public Map<String, Object> work;
public List<PubResponse.Job> jobList;
public PubResponse.Job[] jobs;
如果實(shí)體類中的集合中存放的是實(shí)體類,并且這個(gè)實(shí)體類標(biāo)注了@JsonSensitive注解,則會(huì)對(duì)嵌套實(shí)體類中標(biāo)注了@JsonSimField、@JsonFlexField注解的字段進(jìn)行脫敏處理;同樣如果最外層是集合、數(shù)組、key-value類型則也會(huì)對(duì)內(nèi)部嵌套的實(shí)體類進(jìn)行脫敏處理;
本文只對(duì)脫敏SDK做大概的闡述,如果你需要源碼可以到個(gè)人GitHub上去拉;本文的示例是對(duì)當(dāng)前實(shí)體類對(duì)象本身進(jìn)行脫敏處理,返回的還是原來(lái)的對(duì)象本身,個(gè)人GitHub示例中還有一個(gè)返回是非當(dāng)前對(duì)象的SDK工具類SensitiveUtils;文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-423188.html
GitHub地址:https://github.com/mingyang66/spring-parent文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-423188.html
到了這里,關(guān)于解鎖新技能《Java基于注解的脫敏實(shí)現(xiàn)組件SDK》的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!