使用十一种设计模式实现 基于Jackson注解的 完美数据脱敏方案

时间:2025-02-15 20:21:30
@UtilityClass class SensitiveDeals { String none(String source, Sensitive sensitive) { char hidedChar = sensitive.replacement().charAt(0); char[] chars = new char[source.length()]; Arrays.fill(chars, hidedChar); return new String(chars); } SensitiveDeal createSuffix(int showLength) { return (source, sensitive) -> { char hidedChar = sensitive.replacement().charAt(0); return suffix0(source, showLength, hidedChar); }; } String suffix(String source, Sensitive sensitive) { char hidedChar = sensitive.replacement().charAt(0); return suffix0(source, sensitive.keepTail(), hidedChar); } SensitiveDeal createPrefix(int showLength) { return (source, sensitive) -> { char hidedChar = sensitive.replacement().charAt(0); return prefix0(source, showLength, hidedChar); }; } String prefix(String source, Sensitive sensitive) { char hidedChar = sensitive.replacement().charAt(0); return prefix0(source, sensitive.maskStart(), hidedChar); } SensitiveDeal createWrap(final int maskStart, final int keepTail) { return (source, sensitive) -> { char hidedChar = sensitive.replacement().charAt(0); return wrap0(source, maskStart, keepTail, hidedChar); }; } String wrap(String source, Sensitive sensitive) { char hidedChar = sensitive.replacement().charAt(0); return wrap0(source, sensitive.maskStart(), sensitive.keepTail(), hidedChar); } /** * Pattern 是线程安全的,所以缓存起来。<br> * 实例数量不会有太多,暂时不需要使用复杂缓存策略。 */ Map<String, Pattern> regularCache = new ConcurrentHashMap<>(); SensitiveDeal createRegular(String regular, String replacement) { Assert.notBlank(regular); Pattern pattern = regularCache.computeIfAbsent(regular, Pattern::compile); return (source, sensitive) -> { return regular0(source, pattern, replacement); }; } String regular(String source, Sensitive sensitive) { Assert.notBlank(sensitive.regular()); Assert.notBlank(sensitive.replacement()); Pattern pattern = regularCache.computeIfAbsent(sensitive.regular(), Pattern::compile); return regular0(source, pattern, sensitive.replacement()); } private String suffix0(final String source, final int showLength, final char hidedChar) { if (StringUtils.length(source) <= showLength) { return source; } char[] chars = new char[source.length()]; Arrays.fill(chars, hidedChar); int begin = source.length() - showLength; source.getChars(begin, source.length(), chars, begin); return new String(chars); } private String prefix0(final String source, final int showLength, final char hidedChar) { if (StringUtils.length(source) <= showLength) { return source; } char[] chars = new char[source.length()]; Arrays.fill(chars, hidedChar); source.getChars(0, showLength, chars, 0); return new String(chars); } private String wrap0(final String source, final int maskStart, final int keepTail, final char hidedChar) { if (source.length() <= maskStart + keepTail + 1) { char[] chars = source.toCharArray(); chars[source.length() / 2] = hidedChar; return new String(chars); } char[] chars = new char[source.length()]; Arrays.fill(chars, hidedChar); source.getChars(0, maskStart, chars, 0); int begin = source.length() - keepTail; source.getChars(begin, source.length(), chars, begin); return new String(chars); } private String regular0(final String source, final Pattern pattern, final String replacement) { Matcher matcher = pattern.matcher(source); if (!matcher.matches()) { return source; } return matcher.replaceAll(replacement); } /** * 自定义脱敏的实例。肯定线程安全。。<br> * 实例数量不会有太多,暂时不需要使用复杂缓存策略。 */ Map<Class<? extends SensitiveDeal>, SensitiveDeal> customerCache = new ConcurrentHashMap<>(); String customerCommon(String source, Sensitive sensitive) { Class<? extends SensitiveDeal> clz = sensitive.dealType(); Objects.requireNonNull(clz); SensitiveDeal deal = customerCache.computeIfAbsent(clz, cls -> { try { return cls.newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new IllegalArgumentException("脱敏策略无法实例化:" + cls.getName(), e); } }); return deal.apply(source, sensitive); } String userName(String source, Sensitive sensitive) { if (StringUtils.length(source) < 2) { return source; } char hidedChar = sensitive.replacement().charAt(0); if (source.length() < 5) { char[] chars = source.toCharArray(); chars[1] = hidedChar; return new String(chars); } char[] chars = new char[source.length()]; Arrays.fill(chars, hidedChar); source.getChars(0, 1, chars, 0); int begin = source.length() - 2; source.getChars(begin, source.length(), chars, begin); return new String(chars); } String email(String source, Sensitive sensitive) { int index = StringUtils.indexOf(source, "@"); if (index <= 0) { return source; } char hidedChar = sensitive.replacement().charAt(0); String acc = source.substring(0, index); String host = source.substring(index); return wrap0(acc, 2, 1, hidedChar) + host; } }