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 }