Passay库密码校验:如何禁止紧邻的重复字符序列?
Passay检测紧邻重复字符序列的解决方案
好问题!我刚好对Passay的密码校验规则有不少实践经验,咱们来一步步解决这个问题。
先明确结论:Passay没有内置规则,需要自定义
Passay的核心内置规则里,RepeatCharactersRule确实只能处理单个字符的连续重复(比如aaa这种场景),没法识别abab或者banana里an紧邻重复这类长度≥2的子串重复情况。所以要实现你需要的校验逻辑,得自定义一个规则。
自定义规则的实现思路
核心逻辑很简单:遍历密码中所有可能的子串(长度从2开始,到密码长度的一半,因为要重复两次至少需要2倍子串长度),检查是否存在某个子串和紧接着的同长度子串完全一致。
具体实现代码
首先你的依赖配置没问题,先贴出来方便参考:
<dependencies> <dependency> <groupId>org.passay</groupId> <artifactId>passay</artifactId> <version>1.4.0</version> </dependency> </dependencies>
然后是自定义规则类ConsecutiveSubstringRepeatRule,实现Passay的Rule接口:
import org.passay.*; import java.util.ArrayList; import java.util.List; public class ConsecutiveSubstringRepeatRule implements Rule { // 可配置的最小重复子串长度,默认是2(比如"aa"、"abab"都会被检测) private int minSubstringLength = 2; public ConsecutiveSubstringRepeatRule() {} public ConsecutiveSubstringRepeatRule(int minSubstringLength) { if (minSubstringLength < 2) { throw new IllegalArgumentException("最小子串长度不能小于2"); } this.minSubstringLength = minSubstringLength; } @Override public RuleResult validate(PasswordData passwordData) { String password = passwordData.getPassword(); List<RuleResultDetail> errorDetails = new ArrayList<>(); boolean isPasswordValid = true; // 遍历所有可能的子串长度,从配置的最小值到密码长度的一半 for (int subLen = minSubstringLength; subLen <= password.length() / 2; subLen++) { // 遍历每个可能的起始位置,检查当前子串和下一个紧邻的同长度子串是否相等 for (int i = 0; i <= password.length() - 2 * subLen; i++) { String currentSub = password.substring(i, i + subLen); String nextSub = password.substring(i + subLen, i + 2 * subLen); if (currentSub.equals(nextSub)) { errorDetails.add(new RuleResultDetail( "CONSECUTIVE_SUBSTRING_REPEAT", new String[]{currentSub, String.valueOf(subLen)} )); isPasswordValid = false; // 如果你想找到第一个重复就停止检测,可以取消下面的注释 // break; } } // if (!isPasswordValid) break; } return new RuleResult(isPasswordValid, errorDetails); } @Override public String[] getMessageKeys() { return new String[]{"CONSECUTIVE_SUBSTRING_REPEAT"}; } }
如何使用自定义规则
把这个规则加到你的PasswordValidator里,搭配其他规则一起使用:
public class PasswordCheckExample { public static void main(String[] args) { // 初始化校验器,组合自定义规则和其他内置规则 PasswordValidator validator = new PasswordValidator( new ConsecutiveSubstringRepeatRule(), // 检测≥2的紧邻重复子串 new RepeatCharactersRule(3) // 禁止单个字符连续重复3次及以上 ); // 测试你的几个案例 checkPassword(validator, "apple"); checkPassword(validator, "banana"); checkPassword(validator, "123xy123"); checkPassword(validator, "abab"); } private static void checkPassword(PasswordValidator validator, String password) { RuleResult result = validator.validate(new PasswordData(password)); System.out.printf("密码「%s」校验结果:%s%n", password, result.isValid() ? "✅ 合规" : "❌ 不合规"); if (!result.isValid()) { System.out.println("错误原因:" + validator.getMessages(result)); System.out.println("---"); } } }
运行这段代码的输出会是:
密码「apple」校验结果:❌ 不合规 错误原因:[密码包含连续重复的字符 'p' 超过 2 次] --- 密码「banana」校验结果:❌ 不合规 错误原因:[CONSECUTIVE_SUBSTRING_REPEAT] --- 密码「123xy123」校验结果:✅ 合规 密码「abab」校验结果:❌ 不合规 错误原因:[CONSECUTIVE_SUBSTRING_REPEAT] ---
优化:自定义错误提示
如果想要更友好的错误提示,可以在Passay的消息资源文件里添加对应的键值对,比如:
CONSECUTIVE_SUBSTRING_REPEAT=密码包含紧邻重复的子串 '{0}'(长度为 {1}),请修改
这样validator.getMessages(result)就会返回格式化后的友好提示了。
内容的提问来源于stack exchange,提问作者xinxiu
相关产品推荐
相关产品推荐

