註解進行資料脫敏處理
阿新 • • 發佈:2022-12-01
1.定義註解和列舉類
package com.joolun.common.sensitive; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; /** * 脫敏註解 * * @author JooLun * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html **/ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @JacksonAnnotationsInside @JsonSerialize(using = SensitiveSerialize.class) public @interface Sensitive {/** * 脫敏資料型別 */ SensitiveTypeEnum type(); }
package com.joolun.common.sensitive; /** * 敏感資訊列舉類 * * @author JooLun * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html **/ public enum SensitiveTypeEnum { /** * 使用者名稱, 李*天, 張* */ CHINESE_NAME, /** * 手機號, 185****1653*/ MOBILE_PHONE, /** * 電子郵件, r*****[email protected] */ EMAIL, /** * 密碼, ****** */ PASSWORD, /** * 金鑰, 最後三位其他都是*** */ KEY }
2.脫敏工具類和業務類
package com.joolun.common.sensitive; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import com.joolun.common.utils.SensitiveUtils; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import java.io.IOException; import java.util.Objects; /** * @author JooLun * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html * 脫敏序列化 */ @NoArgsConstructor @AllArgsConstructor public class SensitiveSerialize extends JsonSerializer<String> implements ContextualSerializer { private SensitiveTypeEnum type; @Override public void serialize(final String originStr, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException { switch (type) { case CHINESE_NAME: jsonGenerator.writeString(SensitiveUtils.chineseName(originStr)); break; case MOBILE_PHONE: jsonGenerator.writeString(SensitiveUtils.mobilePhone(originStr)); break; case EMAIL: jsonGenerator.writeString(SensitiveUtils.email(originStr)); break; case PASSWORD: jsonGenerator.writeString(SensitiveUtils.password(originStr)); break; case KEY: jsonGenerator.writeString(SensitiveUtils.key(originStr)); break; default: throw new IllegalArgumentException("未定義的敏感資訊列舉類" + type); } } @Override public JsonSerializer<?> createContextual(final SerializerProvider serializerProvider, final BeanProperty beanProperty) throws JsonMappingException { if (beanProperty != null) { if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) { Sensitive sensitive = beanProperty.getAnnotation(Sensitive.class); if (sensitive == null) { sensitive = beanProperty.getContextAnnotation(Sensitive.class); } if (sensitive != null) { return new SensitiveSerialize(sensitive.type()); } } return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty); } return serializerProvider.findNullValueSerializer(null); } }
package com.joolun.common.utils; import cn.hutool.core.util.StrUtil; /** * 資料脫敏工具類 * * @Author: JooLun * @Author: https://www.cnblogs.com/xiluonanfeng/p/10183926.html * @Date: 2021/7/19 16:21 */ public class SensitiveUtils { /** * 預設填充字元 */ public static final String DEFAULT_PAD_STR = "*"; /** * 資料脫敏 * */ public static String process(String data) { return process(data, 2, 1, DEFAULT_PAD_STR); } /** * 資料脫敏 * */ public static String process(String data, Integer leftLen, Integer rightLen) { return process(data, leftLen, rightLen, DEFAULT_PAD_STR); } /** * 對字串進行脫敏操作 * @param originStr 原始字串 * @param prefixNoMaskLen 左側需要保留幾位明文欄位 * @param suffixNoMaskLen 右側需要保留幾位明文欄位 * @param maskStr 用於遮罩的字串, 如'*' * @return 脫敏後結果 */ public static String process(String originStr, int prefixNoMaskLen, int suffixNoMaskLen, String maskStr) { if (originStr == null) { return null; } StringBuilder sb = new StringBuilder(); for (int i = 0, n = originStr.length(); i < n; i++) { if (i < prefixNoMaskLen) { sb.append(originStr.charAt(i)); continue; } if (i > (n - suffixNoMaskLen - 1)) { sb.append(originStr.charAt(i)); continue; } sb.append(maskStr); } return sb.toString(); } /** * 中文姓名只顯示最後一個漢字 * @param fullName 姓名 * @return */ public static String chineseName(String fullName) { if (fullName == null) { return null; } return process(fullName, 0, 1, DEFAULT_PAD_STR); } /** * 手機號碼前三位,後四位,如186****2356 * @param num 手機號碼 * @return */ public static String mobilePhone(String num) { return process(num, 0, 4, DEFAULT_PAD_STR); } /** * 地址只顯示到地區 * @param address 地址 * @return */ public static String address(String address) { return process(address, 6, 0, DEFAULT_PAD_STR); } /** * 電子郵箱 僅顯示第一個字母,@後面的地址顯示,比如:r**@qq.com * @param email 電子郵箱 * @return */ public static String email(String email) { if (email == null) { return null; } int index = StrUtil.indexOf(email, '@'); if (index <= 1) { return email; } String preEmail = process(email.substring(0, index), 1, 0, DEFAULT_PAD_STR); return preEmail + email.substring(index); } /** * 密碼的全部字元,如:****** * @param password 密碼 * @return */ public static String password(String password) { if (password == null) { return null; } return "******"; } /** * 金鑰除了最後三位,全部,比如:***klo * @param key 金鑰 * @return 結果 */ public static String key(String key) { if (key == null) { return null; } int viewLength = 6; StringBuilder tmpKey = new StringBuilder(process(key, 0, 3, DEFAULT_PAD_STR)); if (tmpKey.length() > viewLength) { return tmpKey.substring(tmpKey.length() - viewLength); } else if (tmpKey.length() < viewLength) { int buffLength = viewLength - tmpKey.length(); for (int i = 0; i < buffLength; i++) { tmpKey.insert(0, DEFAULT_PAD_STR); } return tmpKey.toString(); } else { return tmpKey.toString(); } } public static void main(String[] args) { String s = mobilePhone("18653653621"); System.out.println(s); } }
3.實體類使用
/** * 電話號碼 */ @ApiModelProperty(value = "電話號碼") @Sensitive(type = SensitiveTypeEnum.MOBILE_PHONE) private String telNum;