Springboot实现数据脱敏

1. 敏感信息处理配置类

java 复制代码
@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;
}

2. 脱敏类型枚举

java 复制代码
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"),
	IP_ADDRESS("IP地址", "(\\d{1,3}\\.\\d{1,3})\\.\\d{1,3}\\.\\d{1,3}", "$1.***.***"),
	MAC_ADDRESS("MAC地址", "([0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}):[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}:[0-9A-Fa-f]{2}", "$1:****"),
	;

	private final String replacement;
	private final Pattern pattern;

	SensitiveType(String ignore, String regex, String replacement) {
		this.replacement = replacement;
		this.pattern = Pattern.compile(regex);
	}

	/**
	 * 替换文本
	 * @param content content
	 * @return 替换后的内容
	 */
	public String replaceAll(String content) {
		return this.pattern.matcher(content).replaceAll(this.replacement);
	}
}

3. 敏感词分组枚举

java 复制代码
@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", "sql", "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);
	}
}

4. 敏感信息处理工具类

java 复制代码
/**
 * <p>
 * 支持以下功能:
 * 1. 内置敏感类型处理(手机号、邮箱、身份证等)
 * 2. 自定义正则表达式处理
 * 3. 敏感词处理
 * 4. 支持按行处理或整体处理
 * 5. 支持自定义替换符
 * 6. 支持泛型返回值
 * </p>
 */
public class SensitiveUtil {
	private static final String DEFAULT_REPLACEMENT = "******";
	private static final String LINE_SEPARATOR = System.lineSeparator();

	// 预编译的默认配置
	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();

	/**
	 * 使用默认配置处理敏感信息
	 *
	 * @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) {
			result = type.replaceAll(result);
		}
		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;
	}
}
相关推荐
luming-021 天前
java报错解决:sun.net.utils不存
java·经验分享·bug·.net·intellij-idea
北海有初拥1 天前
Python基础语法万字详解
java·开发语言·python
alonewolf_991 天前
Spring IOC容器扩展点全景:深入探索与实践演练
java·后端·spring
super_lzb1 天前
springboot打war包时将外部配置文件打入到war包内
java·spring boot·后端·maven
毛小茛1 天前
芋道管理系统学习——项目结构
java·学习
天远云服1 天前
Go语言高并发实战:集成天远手机号码归属地核验API打造高性能风控中台
大数据·开发语言·后端·golang
东北小狐狸-Hellxz1 天前
解决java客户端连接ssh失败问题
java·网络·ssh
悟能不能悟1 天前
HttpServletRequest request获取整个headers有什么方法
java
__万波__1 天前
二十三种设计模式(二十)--解释器模式
java·设计模式·解释器模式