新增脱敏工具类

This commit is contained in:
smallchill 2025-01-04 22:13:49 +08:00
parent 61a4450d65
commit 940a120b8d
4 changed files with 436 additions and 0 deletions

View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.tool.sensitive;
import lombok.Builder;
import lombok.Data;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
/**
* 敏感信息处理配置类
*
* @author BladeX
*/
@Builder
@Data
public class SensitiveConfig {
// 启用的内置正则脱敏类型
private Set<SensitiveType> sensitiveTypes;
// 启用的内置敏感词分组
private Set<SensitiveWord> sensitiveWords;
// 自定义敏感词列表
private List<String> customSensitiveWords;
// 自定义正则表达式脱敏规则
private Map<String, Pattern> customPatterns;
// 自定义替换文本可选有默认值
private String replacement;
// 是否按行处理
private boolean processLineByLine;
}

View File

@ -0,0 +1,43 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.tool.sensitive;
import lombok.Getter;
/**
* 脱敏类型枚举.
*
* @author BladeX
*/
@Getter
public enum SensitiveType {
GLOBAL("全局", "(.{2}).*(.{2})", "$1****$2"),
MOBILE("手机号", "(\\d{3})\\d{4}(\\d{4})", "$1****$2"),
EMAIL("电子邮箱", "(\\w{2})\\w+(@\\w+\\.\\w+)", "$1****$2"),
ID_CARD("身份证号", "(\\d{4})\\d{10}(\\w{4})", "$1**********$2"),
BANK_CARD("银行卡号", "(\\d{4})\\d+(\\d{4})", "$1****$2"),
;
private final String desc;
private final String regex;
private final String replacement;
SensitiveType(String desc, String regex, String replacement) {
this.desc = desc;
this.regex = regex;
this.replacement = replacement;
}
}

View File

@ -0,0 +1,286 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.tool.sensitive;
import org.springblade.core.tool.utils.CollectionUtil;
import org.springblade.core.tool.utils.StringUtil;
import java.util.*;
import java.util.regex.Pattern;
/**
* 敏感信息处理工具类
* <p>
* 支持以下功能
* 1. 内置敏感类型处理手机号邮箱身份证等
* 2. 自定义正则表达式处理
* 3. 敏感词处理
* 4. 支持按行处理或整体处理
* 5. 支持自定义替换符
* 6. 支持泛型返回值
* </p>
*
* @author BladeX
*/
public class SensitiveUtil {
private static final String DEFAULT_REPLACEMENT = "******";
private static final String LINE_SEPARATOR = System.lineSeparator();
// 预编译的正则表达式
private static final Map<SensitiveType, Pattern> PATTERN_CACHE = new EnumMap<>(SensitiveType.class);
// 预编译的默认配置
private static final SensitiveConfig DEFAULT_CONFIG = SensitiveConfig.builder()
.sensitiveTypes(EnumSet.of(
SensitiveType.MOBILE,
SensitiveType.ID_CARD,
SensitiveType.EMAIL,
SensitiveType.BANK_CARD
))
.sensitiveWords(EnumSet.of(
SensitiveWord.SECURE,
SensitiveWord.AUTHENTICATION
))
.processLineByLine(true)
.replacement(DEFAULT_REPLACEMENT)
.build();
static {
// 预编译所有内置的正则表达式
for (SensitiveType type : SensitiveType.values()) {
PATTERN_CACHE.put(type, Pattern.compile(type.getRegex()));
}
}
/**
* 使用默认配置处理敏感信息
*
* @param content 待处理内容
* @return 处理后的结果
*/
public static String process(String content) {
return process(content, DEFAULT_CONFIG);
}
/**
* 使用自定义配置处理敏感信息
*
* @param content 待处理内容
* @param config 自定义配置
* @return 处理后的结果
*/
public static String process(String content, SensitiveConfig config) {
if (StringUtil.isBlank(content)) {
return content;
}
String processedContent = content;
String placeholder = StringUtil.isBlank(config.getReplacement()) ?
DEFAULT_REPLACEMENT : config.getReplacement();
// 1. 处理内置敏感类型
if (!CollectionUtil.isEmpty(config.getSensitiveTypes())) {
processedContent = processRegexPatterns(processedContent, config.getSensitiveTypes());
}
// 2. 处理自定义正则
if (!CollectionUtil.isEmpty(config.getCustomPatterns())) {
processedContent = processCustomPatterns(processedContent,
config.getCustomPatterns(),
placeholder);
}
// 3. 处理敏感词
if (!CollectionUtil.isEmpty(config.getSensitiveWords())) {
List<String> words = getSensitiveWords(config.getSensitiveWords());
processedContent = processSensitiveWords(processedContent,
words,
placeholder,
config.isProcessLineByLine());
}
return processedContent;
}
/**
* 处理单个敏感类型
*
* @param content 待处理内容
* @param type 敏感类型
* @return 处理后的结果
*/
public static String process(String content, SensitiveType type) {
if (StringUtil.isBlank(content) || type == null) {
return content;
}
return processRegexPatterns(content, Collections.singleton(type));
}
/**
* 处理多个敏感类型
*
* @param content 待处理内容
* @param types 敏感类型集合
* @return 处理后的结果
*/
public static String process(String content, Set<SensitiveType> types) {
if (StringUtil.isBlank(content) || CollectionUtil.isEmpty(types)) {
return content;
}
return processRegexPatterns(content, types);
}
/**
* 使用自定义正则处理使用默认替换符
*
* @param content 待处理内容
* @param regex 正则表达式
* @return 处理后的结果
*/
public static String processWithRegex(String content, String regex) {
return processWithRegex(content, regex, DEFAULT_REPLACEMENT);
}
/**
* 使用自定义正则处理使用自定义替换符
*
* @param content 待处理内容
* @param regex 正则表达式
* @param replacement 替换内容
* @return 处理后的结果
*/
public static String processWithRegex(String content, String regex, String replacement) {
if (StringUtil.isBlank(content) || StringUtil.isBlank(regex)) {
return content;
}
Pattern pattern = Pattern.compile(regex);
return pattern.matcher(content).replaceAll(replacement);
}
/**
* 处理敏感词使用默认配置
*
* @param content 待处理内容
* @param words 敏感词列表
* @return 处理后的结果
*/
public static String processWithWords(String content, List<String> words) {
return processWithWords(content, words, DEFAULT_REPLACEMENT, true);
}
/**
* 处理敏感词使用完整参数
*
* @param content 待处理内容
* @param words 敏感词列表
* @param placeholder 替换符
* @param processLineByLine 是否按行处理
* @return 处理后的结果
*/
public static String processWithWords(String content,
List<String> words,
String placeholder,
boolean processLineByLine) {
if (StringUtil.isBlank(content) || CollectionUtil.isEmpty(words)) {
return content;
}
return processSensitiveWords(content, words, placeholder, processLineByLine);
}
/**
* 处理正则表达式
*/
private static String processRegexPatterns(String content, Set<SensitiveType> types) {
String result = content;
for (SensitiveType type : types) {
Pattern pattern = PATTERN_CACHE.get(type);
result = pattern.matcher(result).replaceAll(type.getReplacement());
}
return result;
}
/**
* 处理自定义正则表达式
*/
private static String processCustomPatterns(String content,
Map<String, Pattern> patterns,
String placeholder) {
String result = content;
for (Pattern pattern : patterns.values()) {
result = pattern.matcher(result).replaceAll(placeholder);
}
return result;
}
/**
* 获取敏感词列表
*/
private static List<String> getSensitiveWords(Set<SensitiveWord> groups) {
List<String> words = new ArrayList<>();
for (SensitiveWord group : groups) {
words.addAll(group.getWords());
}
return words;
}
/**
* 处理敏感词
*/
private static String processSensitiveWords(String content,
List<String> words,
String placeholder,
boolean processLineByLine) {
return processLineByLine ?
maskSensitiveLines(content, words, placeholder) :
maskSensitiveContent(content, words, placeholder);
}
/**
* 按行处理敏感词
*/
private static String maskSensitiveLines(String content,
List<String> words,
String placeholder) {
String[] lines = content.split(LINE_SEPARATOR);
StringBuilder result = new StringBuilder();
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
boolean containsSensitive = words.stream()
.anyMatch(word -> line.toLowerCase().contains(word.toLowerCase()));
result.append(containsSensitive ? placeholder : line);
if (i < lines.length - 1) {
result.append(LINE_SEPARATOR);
}
}
return result.toString();
}
/**
* 处理整体内容中的敏感词
*/
private static String maskSensitiveContent(String content,
List<String> words,
String placeholder) {
boolean containsSensitive = words.stream()
.anyMatch(word -> content.toLowerCase().contains(word.toLowerCase()));
return containsSensitive ? placeholder : content;
}
}

View File

@ -0,0 +1,56 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
* <p>
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springblade.core.tool.sensitive;
import lombok.Getter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 敏感词分组枚举.
*
* @author BladeX
*/
@Getter
public enum SensitiveWord {
// 安全敏感词组
SECURE(Arrays.asList(
// 认证信息类
"password", "pwd", "token", "secret", "bearer", "key",
// API相关
"api_key", "access_token", "refresh_token", "auth_token",
// 加密相关
"private_key", "public_key", "salt", "hash",
// 安全相关
"security", "certificate", "credentials",
// 数据库相关
"connection_string", "jdbc", "database_url"
)),
// 身份验证相关敏感词
AUTHENTICATION(Arrays.asList(
"otp", "verification_code", "auth_code", "mfa_token"
));
private final List<String> words;
SensitiveWord(List<String> words) {
this.words = Collections.unmodifiableList(words);
}
}