1 import cn.hutool.core.util.StrUtil; 2 3 /** 4 * 脱敏工具类 5 **/ 6 public class DesensitizedUtils { 7 8 /** 9 * 对字符串进行脱敏操作 10 * 11 * @param origin 原始字符串 12 * @param prefixNoMaskLen 左侧需要保留几位明文字段 13 * @param suffixNoMaskLen 右侧需要保留几位明文字段 14 * @param maskStr 用于遮罩的字符串, 如'*' 15 * @return 脱敏后结果 16 */ 17 public static String desValue(String origin, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) { 18 if (origin == null) { 19 return null; 20 } 21 22 StringBuilder sb = new StringBuilder(); 23 for (int i = 0, n = origin.length(); i < n; i++) { 24 if (i < prefixNoMaskLen) { 25 sb.append(origin.charAt(i)); 26 continue; 27 } 28 if (i > (n - suffixNoMaskLen - 1)) { 29 sb.append(origin.charAt(i)); 30 continue; 31 } 32 sb.append(maskStr); 33 } 34 return sb.toString(); 35 } 36 37 /** 38 * 【中文姓名】只显示最后一个汉字,其他隐藏为星号,比如:**梦 39 * 40 * @param fullName 姓名 41 * @return 结果 42 */ 43 public static String chineseName(String fullName) { 44 if (fullName == null) { 45 return null; 46 } 47 return desValue(fullName, 0, 1, "*"); 48 } 49 50 /** 51 * 【身份证号】显示前六位, 四位,其他隐藏。共计18位或者15位,比如:340304*******1234 52 * 53 * @param id 身份证号码 54 * @return 结果 55 */ 56 public static String idCardNum(String id) { 57 return desValue(id, 6, 4, "*"); 58 } 59 60 /** 61 * 【固定电话】后四位,其他隐藏,比如 ****1234 62 * 63 * @param num 固定电话 64 * @return 结果 65 */ 66 public static String fixedPhone(String num) { 67 return desValue(num, 0, 4, "*"); 68 } 69 70 /** 71 * 【手机号码】前三位,后四位,其他隐藏,比如135****6810 72 * 73 * @param num 手机号码 74 * @return 结果 75 */ 76 public static String mobilePhone(String num) { 77 return desValue(num, 3, 4, "*"); 78 } 79 80 /** 81 * 【地址】只显示到地区,不显示详细地址,比如:北京市海淀区**** 82 * 83 * @param address 地址 84 * @return 结果 85 */ 86 public static String address(String address) { 87 return desValue(address, 6, 0, "*"); 88 } 89 90 /** 91 * 【电子邮箱 邮箱前缀仅显示第一个字母,前缀其他隐藏,用星号代替,@及后面的地址显示,比如:d**@126.com 92 * 93 * @param email 电子邮箱 94 * @return 结果 95 */ 96 public static String email(String email) { 97 if (email == null) { 98 return null; 99 } 100 int index = StrUtil.indexOf(email, '@'); 101 if (index <= 1) { 102 return email; 103 } 104 String preEmail = desValue(email.substring(0, index), 1, 0, "*"); 105 return preEmail + email.substring(index); 106 107 } 108 109 /** 110 * 【银行卡号】前六位,后四位,其他用星号隐藏每位1个星号,比如:622260**********1234 111 * 112 * @param cardNum 银行卡号 113 * @return 结果 114 */ 115 public static String bankCard(String cardNum) { 116 return desValue(cardNum, 6, 4, "*"); 117 } 118 119 /** 120 * 【密码】密码的全部字符都用*代替,比如:****** 121 * 122 * @param password 密码 123 * @return 结果 124 */ 125 public static String password(String password) { 126 if (password == null) { 127 return null; 128 } 129 return "******"; 130 } 131 132 /** 133 * 【密钥】密钥除了最后三位,全部都用*代替,比如:***xdS 134 * 脱敏后长度为6,如果明文长度不足三位,则按实际长度显示,剩余位置补* 135 * 136 * @param key 密钥 137 * @return 结果 138 */ 139 public static String key(String key) { 140 if (key == null) { 141 return null; 142 } 143 int viewLength = 6; 144 StringBuilder tmpKey = new StringBuilder(desValue(key, 0, 3, "*")); 145 if (tmpKey.length() > viewLength) { 146 return tmpKey.substring(tmpKey.length() - viewLength); 147 } else if (tmpKey.length() < viewLength) { 148 int buffLength = viewLength - tmpKey.length(); 149 for (int i = 0; i < buffLength; i++) { 150 tmpKey.insert(0, "*"); 151 } 152 return tmpKey.toString(); 153 } else { 154 return tmpKey.toString(); 155 } 156 } 157 158 }
1 /** 2 * 对象脱敏注解 3 * 4 * @author mayee 5 * @version v1.0 6 **/ 7 @Retention(RetentionPolicy.RUNTIME) 8 @Target(ElementType.FIELD) 9 @JacksonAnnotationsInside 10 @JsonSerialize(using = SensitiveSerialize.class) 11 public @interface Sensitive { 12 13 /** 14 * 脱敏数据类型, 非Customer时, 将忽略 refixNoMaskLen 和 suffixNoMaskLen 和 maskStr 15 */ 16 SensitiveTypeEnum type() default SensitiveTypeEnum.CUSTOMER; 17 18 /** 19 * 前置不需要打码的长度 20 */ 21 int prefixNoMaskLen() default 0; 22 23 /** 24 * 后置不需要打码的长度 25 */ 26 int suffixNoMaskLen() default 0; 27 28 /** 29 * 用什么打码 30 */ 31 String maskStr() default "*"; 32 33 }
32 33 /** 34 * @author lengleng 35 * @date 2019-08-13 36 * <p> 37 * 脱敏序列化 38 */ 39 @NoArgsConstructor 40 @AllArgsConstructor 41 public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer { 42 43 private SensitiveTypeEnum type; 44 private Integer prefixNoMaskLen; 45 private Integer suffixNoMaskLen; 46 private String maskStr; 47 48 @Override 49 public void serialize(final String origin, final JsonGenerator jsonGenerator, 50 final SerializerProvider serializerProvider) throws IOException { 51 switch (type) { 52 case CHINESE_NAME: 53 jsonGenerator.writeString(DesensitizedUtils.chineseName(origin)); 54 break; 55 case ID_CARD: 56 jsonGenerator.writeString(DesensitizedUtils.idCardNum(origin)); 57 break; 58 case FIXED_PHONE: 59 jsonGenerator.writeString(DesensitizedUtils.fixedPhone(origin)); 60 break; 61 case MOBILE_PHONE: 62 jsonGenerator.writeString(DesensitizedUtils.mobilePhone(origin)); 63 break; 64 case ADDRESS: 65 jsonGenerator.writeString(DesensitizedUtils.address(origin)); 66 break; 67 case EMAIL: 68 jsonGenerator.writeString(DesensitizedUtils.email(origin)); 69 break; 70 case BANK_CARD: 71 jsonGenerator.writeString(DesensitizedUtils.bankCard(origin)); 72 break; 73 case PASSWORD: 74 jsonGenerator.writeString(DesensitizedUtils.password(origin)); 75 break; 76 case KEY: 77 jsonGenerator.writeString(DesensitizedUtils.key(origin)); 78 break; 79 case CUSTOMER: 80 jsonGenerator.writeString(DesensitizedUtils.desValue(origin, prefixNoMaskLen, suffixNoMaskLen, maskStr)); 81 break; 82 default: 83 throw new IllegalArgumentException("Unknow sensitive type enum " + type); 84 } 85 } 86 87 @Override 88 public JsonSerializer<?> createContextual(final SerializerProvider serializerProvider, 89 final BeanProperty beanProperty) throws JsonMappingException { 90 if (beanProperty != null) { 91 if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) { 92 Sensitive sensitive = beanProperty.getAnnotation(Sensitive.class); 93 if (sensitive == null) { 94 sensitive = beanProperty.getContextAnnotation(Sensitive.class); 95 } 96 if (sensitive != null) { 97 return new SensitiveSerialize(sensitive.type(), sensitive.prefixNoMaskLen(), sensitive.suffixNoMaskLen(), sensitive.maskStr()); 98 } 99 } 100 return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty); 101 } 102 return serializerProvider.findNullValueSerializer(null); 103 } 104 }
1 /** 2 * 敏感信息枚举类 3 * 4 * @author mayee 5 * @version v1.0 6 **/ 7 public enum SensitiveTypeEnum { 8 9 /** 10 * 自定义 11 */ 12 CUSTOMER, 13 /** 14 * 用户名, 刘*华, 徐* 15 */ 16 CHINESE_NAME, 17 /** 18 * 身份证号, 110110********1234 19 */ 20 ID_CARD, 21 /** 22 * 座机号, ****1234 23 */ 24 FIXED_PHONE, 25 /** 26 * 手机号, 176****1234 27 */ 28 MOBILE_PHONE, 29 /** 30 * 地址, 北京******** 31 */ 32 ADDRESS, 33 /** 34 * 电子邮件, s*****o@xx.com 35 */ 36 EMAIL, 37 /** 38 * 银行卡, 622202************1234 39 */ 40 BANK_CARD, 41 /** 42 * 密码, 永远是 ******, 与长度无关 43 */ 44 PASSWORD, 45 /** 46 * 密钥, 永远是 ******, 与长度无关 47 */ 48 KEY 49 50 51 }