Un projet SpringBoot est actuellement en cours de développement. Ce projet dispose d'un client Web et d'une applet WeChat. Le terminal Web est mis à la disposition du personnel et l'applet WeChat est fournie au public pour qu'il puisse effectuer des réservations. Certaines données sensibles du projet doivent être désensibilisées et transmises à l'applet WeChat pour être consultées par le public.
Dans le projet, puisqu'il y a deux utilisateurs, les autorisations de données pour les deux extrémités sont différentes. Toutes les données peuvent être consultées sur le côté Web, tandis que seules les données désensibilisées peuvent être consultées sur le mini-programme.
Besoin de développer une fonction de désensibilisation universelle
通用脱敏功能
手动进行脱敏操作
支持多种对象,
支持不同字段,并脱敏指定字段
字段的脱敏方式多样
字段的脱敏方式可自定义
使用注解方式
Opération de désensibilisation manuelle
Supports une variété d'objets,
Prend en charge différents champs et désensibilise les champs spécifiés
Il existe différentes manières de désensibiliser les champs
La méthode de désensibilisation sur le terrain peut être personnalisée
méthode d'annotation
pour prendre en charge les champs spécifiés, différents champs, plusieurs opérations de désensibilisation. , et peut être séparé de l'objet. import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义数据脱敏 * * 例如: 身份证,手机号等信息进行模糊处理 * * @author lzddddd */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Sensitive { /** * 脱敏数据类型 */ SensitiveType type() default SensitiveType.CUSTOMER; /** * 前置不需要打码的长度 */ int prefixNoMaskLen() default 0; /** * 后置不需要打码的长度 */ int suffixNoMaskLen() default 0; /** * 用什么打码 */ String symbol() default "*"; }🎜2.1 Énumération de types désensibilisés SensitiveType🎜
public enum SensitiveType { /** * 自定义 */ CUSTOMER, /** * 名称 **/ CHINESE_NAME, /** * 身份证证件号 **/ ID_CARD_NUM, /** * 手机号 **/ MOBILE_PHONE, /** * 固定电话 */ FIXED_PHONE, /** * 密码 **/ PASSWORD, /** * 银行卡号 */ BANKCARD, /** * 邮箱 */ EMAIL, /** * 地址 */ ADDRESS, }🎜2.3 Outil désensibilisé DesensitizedUtils🎜
import com.ruoyi.common.annotation.Sensitive; import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.enums.SensitiveType; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; import java.util.*; @Slf4j public class DesensitizedUtils<T> { /** * 脱敏数据列表 */ private List<T> list; /** * 注解列表 */ private List<Object[]> fields; /** * 实体对象 */ public Class<T> clazz; public DesensitizedUtils(Class<T> clazz) { this.clazz = clazz; } /** * 初始化数据 * * @param list 需要处理数据 */ public void init(List<T> list){ if (list == null) { list = new ArrayList<T>(); } this.list = list; // 得到所有定义字段 createSensitiveField(); } /** * 初始化数据 * * @param t 需要处理数据 */ public void init(T t){ list = new ArrayList<T>(); if (t != null) { list.add(t); } // 得到所有定义字段 createSensitiveField(); } /** * 得到所有定义字段 */ private void createSensitiveField() { this.fields = new ArrayList<Object[]>(); List<Field> tempFields = new ArrayList<>(); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); for (Field field : tempFields) { // 单注解 if (field.isAnnotationPresent(Sensitive.class)) { putToField(field, field.getAnnotation(Sensitive.class)); } // 多注解 // if (field.isAnnotationPresent(Excels.class)) // { // Excels attrs = field.getAnnotation(Excels.class); // Excel[] excels = attrs.value(); // for (Excel excel : excels) // { // putToField(field, excel); // } // } } } /** * 对list数据源将其里面的数据进行脱敏处理 * * @param list * @return 结果 */ public AjaxResult desensitizedList(List<T> list){ if (list == null){ return AjaxResult.error("脱敏数据为空"); } // 初始化数据 this.init(list); int failTimes = 0; for (T t: this.list) { if ((Integer)desensitization(t).get("code") != HttpStatus.SUCCESS){ failTimes++; } } if (failTimes >0){ return AjaxResult.error("脱敏操作中出现失败",failTimes); } return AjaxResult.success(); } /** * 放到字段集合中 */ private void putToField(Field field, Sensitive attr) { if (attr != null) { this.fields.add(new Object[] { field, attr }); } } /** * 脱敏:JavaBean模式脱敏 * * @param t 需要脱敏的对象 * @return */ public AjaxResult desensitization(T t) { if (t == null){ return AjaxResult.error("脱敏数据为空"); } // 初始化数据 init(t); try { // 遍历处理需要进行 脱敏的字段 for (Object[] os : fields) { Field field = (Field) os[0]; Sensitive sensitive = (Sensitive) os[1]; // 设置实体类私有属性可访问 field.setAccessible(true); desensitizeField(sensitive,t,field); } return AjaxResult.success(t); } catch (Exception e) { e.printStackTrace(); log.error("日志脱敏处理失败,回滚,详细信息:[{}]", e); return AjaxResult.error("脱敏处理失败",e); } } /** * 对类的属性进行脱敏 * * @param attr 脱敏参数 * @param vo 脱敏对象 * @param field 脱敏属性 * @return */ private void desensitizeField(Sensitive attr, T vo, Field field) throws IllegalAccessException { if (attr == null || vo == null || field == null){ return ; } // 读取对象中的属性 Object value = field.get(vo); SensitiveType sensitiveType = attr.type(); int prefixNoMaskLen = attr.prefixNoMaskLen(); int suffixNoMaskLen = attr.suffixNoMaskLen(); String symbol = attr.symbol(); //获取属性后现在默认处理的是String类型,其他类型数据可扩展 Object val = convertByType(sensitiveType, value, prefixNoMaskLen, suffixNoMaskLen, symbol); field.set(vo, val); } /** * 以类的属性的get方法方法形式获取值 * * @param o 对象 * @param name 属性名 * @return value * @throws Exception */ private Object getValue(Object o, String name) throws Exception { if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) { Class<?> clazz = o.getClass(); Field field = clazz.getDeclaredField(name); field.setAccessible(true); o = field.get(o); } return o; } /** * 根据不同注解类型处理不同字段 */ private Object convertByType(SensitiveType sensitiveType, Object value, int prefixNoMaskLen, int suffixNoMaskLen, String symbol) { switch (sensitiveType) { case CUSTOMER: value = customer(value, prefixNoMaskLen, suffixNoMaskLen, symbol); break; case CHINESE_NAME: value = chineseName(value, symbol); break; case ID_CARD_NUM: value = idCardNum(value, symbol); break; case MOBILE_PHONE: value = mobilePhone(value, symbol); break; case FIXED_PHONE: value = fixedPhone(value, symbol); break; case PASSWORD: value = password(value, symbol); break; case BANKCARD: value = bankCard(value, symbol); break; case EMAIL: value = email(value, symbol); break; case ADDRESS: value = address(value, symbol); break; } return value; } /*--------------------------下面的脱敏工具类也可以单独对某一个字段进行使用-------------------------*/ /** * 【自定义】 根据设置进行配置 * * @param value 需处理数据 * @param symbol 填充字符 * @return 脱敏后数据 */ public Object customer(Object value, int prefixNoMaskLen, int suffixNoMaskLen, String symbol) { //针对字符串的处理 if (value instanceof String){ return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return value; } /** * 对字符串进行脱敏处理 * * @param s 需处理数据 * @param prefixNoMaskLen 开头展示字符长度 * @param suffixNoMaskLen 结尾展示字符长度 * @param symbol 填充字符 * @return */ private String handleString(String s, int prefixNoMaskLen, int suffixNoMaskLen, String symbol){ // 是否为空 if (StringUtils.isBlank(s)) { return ""; } // 如果设置为空之类使用 * 代替 if (StringUtils.isBlank(symbol)){ symbol = "*"; } // 对长度进行判断 int length = s.length(); if (length > prefixNoMaskLen + suffixNoMaskLen){ String namePrefix = StringUtils.left(s, prefixNoMaskLen); String nameSuffix = StringUtils.right(s, suffixNoMaskLen); s = StringUtils.rightPad(namePrefix, StringUtils.length(s) - suffixNoMaskLen, symbol).concat(nameSuffix); } return s; } /** * 【中文姓名】只显示第一个汉字,其他隐藏为2个星号,比如:李** * * @param value 需处理数据 * @param symbol 填充字符 * @return 脱敏后数据 */ public String chineseName(Object value, String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 开头只展示一个字符 int prefixNoMaskLen = 1; int suffixNoMaskLen = 0; return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } /** * 【身份证号】显示最后四位,其他隐藏。共计18位或者15位,比如:*************1234 * * @param value 需处理数据 * @param symbol 填充字符 * @return 脱敏后数据 */ public String idCardNum(Object value, String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 结尾只展示四个字符 int prefixNoMaskLen = 0; int suffixNoMaskLen = 4; return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } /** * 【固定电话】 显示后四位,其他隐藏,比如:*******3241 * * @param value 需处理数据 * @param symbol 填充字符 * @return 脱敏后数据 */ public String fixedPhone(Object value, String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 结尾只展示四个字符 int prefixNoMaskLen = 0; int suffixNoMaskLen = 4; return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } /** * 【手机号码】前三位,后四位,其他隐藏,比如:135****6810 * * @param value 需处理数据 * @param symbol 填充字符 * @return 脱敏后数据 */ public String mobilePhone(Object value, String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 开头只展示三个字符 结尾只展示四个字符 int prefixNoMaskLen = 3; int suffixNoMaskLen = 4; return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } /** * 【地址】只显示到地区,不显示详细地址,比如:湖南省长沙市岳麓区*** * 只能处理 省市区的数据 * * @param value 需处理数据 * @param symbol 填充字符 * @return */ public String address(Object value, String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 开头只展示九个字符 int prefixNoMaskLen = 9; int suffixNoMaskLen = 0; return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } /** * 【电子邮箱】 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示,比如:d**@126.com * * @param value 需处理数据 * @param symbol 填充字符 * @return 脱敏后数据 */ public String email(Object value, String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 开头只展示一个字符 结尾只展示@及后面的地址 int prefixNoMaskLen = 1; int suffixNoMaskLen = 4; String s = (String) value; if (StringUtils.isBlank(s)) { return ""; } // 获取最后一个@ int lastIndex = StringUtils.lastIndexOf(s, "@"); if (lastIndex <= 1) { return s; } else { suffixNoMaskLen = s.length() - lastIndex; } return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } /** * 【银行卡号】前六位,后四位,其他用星号隐藏每位1个星号,比如:6222600**********1234 * * @param value 需处理数据 * @param symbol 填充字符 * @return 脱敏后数据 */ public String bankCard(Object value, String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 开头只展示六个字符 结尾只展示四个字符 int prefixNoMaskLen = 6; int suffixNoMaskLen = 4; return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } /** * 【密码】密码的全部字符都用*代替,比如:****** * * @param value 需处理数据 * @param symbol 填充字符 * @return */ public String password(Object value,String symbol) { //针对字符串的处理 if (value instanceof String){ // 对前后长度进行设置 默认 开头只展示六个字符 结尾只展示四个字符 int prefixNoMaskLen = 0; int suffixNoMaskLen = 0; return handleString((String) value, prefixNoMaskLen, suffixNoMaskLen, symbol); } return ""; } }🎜3 Exemples d'utilisation 🎜🎜3.1 Objets nécessitant une annotation🎜
public class User { private static final long serialVersionUID = 1L; /** 普通用户ID */ private Long userId; /** 昵称 */ @Sensitive(type = SensitiveType.CUSTOMER,prefixNoMaskLen = 2,suffixNoMaskLen = 1) private String nickName; /** 姓名 */ @Sensitive(type = SensitiveType.CHINESE_NAME) private String userName; /** 身份证 */ @Sensitive(type = SensitiveType.ID_CARD_NUM) private String identityCard; /** 手机号码 */ @Sensitive(type = SensitiveType.MOBILE_PHONE) private String phoneNumber; }🎜3.2 Opération de désensibilisation 🎜
// 脱敏对象 User user = new User(); ...... DesensitizedUtils<User> desensitizedUtils = new DesensitizedUtils<>(User.class); desensitizedUtils.desensitization(user); //脱敏队列 List<User> users = new ArrayList<>(); ...... DesensitizedUtils<User> desensitizedUtils = new DesensitizedUtils<>(User.class); desensitizedUtils.desensitizedList(users);
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!