这是我根据网上资料整理的两种数据脱敏解决方案,各有千秋,都在我都实际环境中使用了,来自网络,回归网络,希望对读到的朋友有帮助。废话少说,下面就开始贴代码
/**
* 脱敏注解
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Desensitization {
/**
* 脱敏规则类型
* @return
*/
DesensitionType type();
/**
* 附加值, 自定义正则表达式等
* @return
*/
String[] attach() default "";
}
/**
* 脱敏规则枚举
*
*/
public enum DesensitionType {
PHONE("phone", "11位手机号", "^(\\d{3})\\d{4}(\\d{4})$", "$1****$2"),
//注意后四位的表达式,因为有的身份证最后一位是X
ID_CARD("idCard", "16或者18身份证号", "^(\\d{4})\\d{8,10}(\\w{4})$", "$1****$2"),
BANK_CARD("bankCardNo", "银行卡号", "^(\\d{4})\\d*(\\d{4})$", "$1****$2"),
REAL_NAME("realName","真实姓名","(?<=.{1}).*(?=.{1})","*"),
EMAIL("email","电子邮箱","(\\w+)\\w{5}@(\\w+)", "$1***@$2"),
CUSTOM("custom", "自定义正则处理", ""),
TRUNCATE("truncate", "字符串截取处理", ""),
;
String type;
String describe;
String[] regular;
DesensitionType(String type, String describe, String... regular) {
this.type = type;
this.describe = describe;
this.regular = regular;
}
public String getType() {
return type;
}
public String getDescribe() {
return describe;
}
public String[] getRegular() {
return regular;
}
}
上面两个类是为了在实体类属性上注解使用的
1.基于mybatis的数据脱敏实现
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.he.annotation.DesensitionType;
import cn.he.annotation.Desensitization;
/**
* mybatis脱敏处理
*
* @author 傻根她弟
*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Intercepts({
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class }),
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class }), })
public class DesensitizationInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(DesensitizationInterceptor.class);
private boolean desensitization = false;//脱敏
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object result = invocation.proceed();
//如果需要对结果脱敏,则执行
if(desensitization) {
if(result instanceof ArrayList>){
List> list = (ArrayList>)result;
return this.desensitization(list);
}else {
return this.desensitization(result);
}
}
return result;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
/**
* 对返回结果脱敏
* @param list
* @return
*/
private List desensitization(List list) {
Class cls = null;
Field[] objFields = null;
if(list != null && list.size()>0) {
for(Object o:list) {
if(cls == null) {
cls = o.getClass();
objFields = cls.getDeclaredFields();
}
if(objFields != null) {
for(Field field:objFields) {
Desensitization desensitization;
if("serialVersionUID".equals(field.getName()))
continue;
if (String.class != field.getType() || (desensitization = field.getAnnotation(Desensitization.class)) == null) {
continue;
}
field.setAccessible(true);
String value = null;
try {
value = field.get(o)!=null?field.get(o).toString():null;
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(value == null)
continue;
List
DesensitionType type = desensitization.type();
switch (type) {
case CUSTOM:
regular = Arrays.asList(desensitization.attach());
break;
case TRUNCATE:
regular = truncateRender(desensitization.attach());
break;
default:
regular = Arrays.asList(type.getRegular());
}
if (regular.size() > 1) {
String match = regular.get(0);
String result = regular.get(1);
if (null != match && result != null && match.length() > 0) {
value = ((String) value).replaceAll(match, result);
try {
field.set(o, value);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
return list;
}
private Object desensitization(Object obj) {
Class cls = null;
Field[] objFields = null;
if(obj != null) {
if(cls == null) {
cls = obj.getClass();
objFields = cls.getDeclaredFields();
if(objFields != null) {
for(Field field:objFields) {
Desensitization desensitization;
if("serialVersionUID".equals(field.getName()))
continue;
if (String.class != field.getType() || (desensitization = field.getAnnotation(Desensitization.class)) == null) {
continue;
}
field.setAccessible(true);
String value = null;
try {
value = field.get(obj)!=null?field.get(obj).toString():null;
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(value == null)
continue;
List
DesensitionType type = desensitization.type();
switch (type) {
case CUSTOM:
regular = Arrays.asList(desensitization.attach());
break;
case TRUNCATE:
regular = truncateRender(desensitization.attach());
break;
default:
regular = Arrays.asList(type.getRegular());
}
if (regular.size() > 1) {
String match = regular.get(0);
String result = regular.get(1);
if (null != match && result != null && match.length() > 0) {
value = ((String) value).replaceAll(match, result);
try {
field.set(obj, value);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
return obj;
}
private List
List
if (null != attachs && attachs.length >1) {
String rule = attachs[0];
String size = attachs[1];
String template, result;
if ("0".equals(rule)) {
template = "^(\\S{%s})(\\S+)$";
result = "$1";
} else if ("1".equals(rule)) {
template = "^(\\S+)(\\S{%s})$";
result = "$2";
} else {
return regular;
}
try {
if (Integer.parseInt(size) > 0) {
regular.add(0, String.format(template, size));
regular.add(1, result);
}
} catch (Exception e) {
logger.warn("ValueDesensitizeFilter truncateRender size {} exception", size);
}
}
return regular;
}
public boolean isDesensitization() {
return desensitization;
}
public void setDesensitization(boolean desensitization) {
this.desensitization = desensitization;
}
}
//===========以上是基于mybatis的脱敏实现==========================
//====================华丽分割线===============================
//===========下面是用法,测试类具体就不写了======================
public class Country implements Serializable{
private static final long serialVersionUID = 1L;
@Desensitization(type = DesensitionType.REAL_NAME)//脱敏定义
private String code;
private String name;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//====================以下是输出效果=================
A*A
A**W
A**G
A**O
A**A
A**B
A**D
中间打了*号;具体方案厉害还有身份证号、手机号、银行卡号的脱敏,感兴趣的读者可以自己试一试。