关于数据脱敏的两种解决方案之一基于mybatis Interceptor的脱敏

原创
2019/09/03 10:16
阅读数 2.9K

这是我根据网上资料整理的两种数据脱敏解决方案,各有千秋,都在我都实际环境中使用了,来自网络,回归网络,希望对读到的朋友有帮助。废话少说,下面就开始贴代码

/**
 *     脱敏注解
 *
 */

@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<String> regular;
                        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<String> regular;
                        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<String> truncateRender(String[] attachs) {
        List<String> regular = new ArrayList<>();
        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的脱敏实现==========================

//====================华丽分割线===============================

//===========下面是用法,测试类具体就不写了======================

<!-- 配置mybatis工厂 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis.xml" />
        <property name="mapperLocations" value="classpath:mapper/**/*.xml" />
        <property name="dataSource" ref="dataSource" />
        <property name="plugins">
            <array>
                <bean class="cn.he.mybatis.plugin.interceptor.DesensitizationInterceptor">
                    <property name="desensitization" value="true"></property> <!-- 在这里设置成true,表示启用mybatis脱敏-->
                </bean>
            </array>
        </property>
    </bean>

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

中间打了*号;具体方案厉害还有身份证号、手机号、银行卡号的脱敏,感兴趣的读者可以自己试一试。
————————————————
版权声明:本文为CSDN博主「傻根她弟」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/godson_2003/article/details/100160528

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部