密码校验
方案二
password: [{ required: true, validator: validatePassword, trigger: 'blur' }],
export function validatePassword(rule, value, callback) {
let strength = 10; // 1-5 weak 6-8 medium 8-10 high
let enoughLen = value && value.length >= 8 && value.length <= 16;
const invalidNumberPattern = /(\d)\1\1|(?:012|123|234|345|456|567|678|789)|(?:987|876|765|654|543|432|321|210)/;
const invalidLetterPatternL = /([a-z])\1\1|(?:abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)|(?:zyx|yxw|xwv|wvu|vut|uts|tsr|srq|rqp|qpo|pon|onm|nml|mlk|lkj|kji|jih|ihg|hgf|gfe|fed|edc|dcb|cba)/i;
const invalidLetterPatternU = /([A-Z])\1\1|(?:ABC|BCD|CDE|DEF|EFG|FGH|GHI|HIJ|IJK|JKL|KLM|LMN|MNO|NOP|OPQ|PQR|QRS|RST|STU|TUV|UVW|VWX|WXY|XYZ)|(?:ZYX|YXW|XWV|WVU|VUT|UTS|TSR|SRQ|RQP|QPO|PON|ONM|NML|MLK|LKJ|KJI|JIH|IHG|HGF|GFE|FED|EDC|DCB|CBA)/i;
if(value) {
// 长度小于8位
if (value.length < 8) strength--;
// 长度大于16位
if (value.length > 17) strength--;
// 没有包含数字
if (!/\d/.test(value)) strength--;
// 没有包含小写字母
if (!/[a-z]/.test(value)) strength--;
// 没有包含大写字母
if (!/[A-Z]/.test(value)) strength--;
// 没有包含特殊字符
if (!/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(value)) strength--;
// 是否在弱口令列表内
if(isWeakPassword(value)) strength--;
// 是否包含3个连续或相同数字(正序,逆序)
if(invalidNumberPattern.test(value)) strength--;
// 是否包含3个连续或相同小写字母(正序,逆序)
if(invalidLetterPatternL.test(value)) strength--;
// 是否包含3个连续或相同大写字母(正序,逆序)
if(invalidLetterPatternU.test(value)) strength--;
}
if(value === '') {
callback(new Error('必填项不能为空!'));
} else if(!enoughLen) {
callback(new Error('密码长度应在[8-16]位之间'))
} else if (strength <= 5) {
callback(new Error('当前密码强度较弱,存在安全风险!'));
} else {
callback();
}
}
/**
* 检查密码是否是常用弱口令
* @param {string} password 待检测的密码
* @returns {boolean} 是否是弱口令
*/
function isWeakPassword(password) {
// 常见弱口令列表(可根据需要扩展)
const weakPasswords = [
'password', '123456', '12345678', '123456789', '12345',
'1234567', '1234567890', 'qwerty', 'abc123', 'admin',
'welcome', 'monkey', 'letmein', 'password1', '123123',
'111111', 'sunshine', 'iloveyou', 'admin123', '123qwe',
'passw0rd', '1234', 'test', '123abc', '000000', 'abcdefgh'
];
// 检查是否在弱口令列表中
if (weakPasswords.includes(password.toLowerCase())) {
return true;
}
// 检查是否是纯数字(6位以上)
if (/^\d{6,}$/.test(password)) {
return true;
}
// 检查是否是纯字母(6位以上)
if (/^[a-zA-Z]{6,}$/.test(password)) {
return true;
}
// 检查是否是连续数字或字母(如123456, abcdef)
if (/(012345|123456|234567|345678|456789|567890|098765|987654|876543|765432|654321|543210|abcdef|bcdefg|cdefgh|defghi|efghij|fghijk|ghijkl|hijklm|ijklmn|jklmno|klmnop|lmnopq|mnopqr|nopqrs|opqrst|pqrstu|qrstuv|rstuvw|stuvwx|tuvwxy|uvwxyz|zyxwv|xwvut|wvuts|vutsr|utsrq|tsrqp|srqpo|rqpon|qponm|ponml|onmlk|nmlkj|mlkji|lkjih|kjihg|jihgf|ihgfe|hgfed|gfedc|fedcb|edcba)/i.test(password)) {
return true;
}
// 检查是否是重复字符(如aaaaaa, 111111)
if (/^([a-zA-Z0-9])\1{5,}$/.test(password)) {
return true;
}
return false;
}
方案一
password: [{ required: true, validator: validatePassword, trigger: 'blur' }],
export function validatePassword(rule, password, callback) {
const WEAK_PASSWORDS = [
'ABCabc123',
'Admin123',
'1qazXSW@',
'aaaBBB111',
// 可继续添加其他常见弱口令
];
const SPECIAL_CHARS = "!@#$%^&*()_+-=[]{}|;:'\",.<>/?`~";
if(password === '') {
callback(new Error('必填项不能为空!'));
}
// 规则1:长度 8 ~ 16 位
if (password.length < 8 || password.length > 16) {
callback(new Error('密码长度必须为8位至16位!'));
}
// 规则3:不能是常用弱口令
const lowerPassword = password.toLowerCase();
if (WEAK_PASSWORDS.some(p => p.toLowerCase() === lowerPassword)) {
callback(new Error('密码属于常用弱口令,请选择更复杂的密码!'));
}
// 检查字符类型
let hasDigit = /\d/.test(password);
let hasSpecial = new RegExp(`[${SPECIAL_CHARS.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}]`).test(password);
let hasUpper = /[A-Z]/.test(password);
let hasLower = /[a-z]/.test(password);
let typeCount = [hasDigit, hasSpecial, hasUpper, hasLower].filter(Boolean).length;
// 规则2:必须包含至少3种类型
if (typeCount < 3) {
callback(new Error('密码必须包含数字、特殊符号、大小写字母中的至少3项!'));
}
// 规则4:不能包含3个连续或相同的数字(正序/逆序)
if (/(012|123|234|345|456|567|678|789|987|876|765|654|543|432|321|210)/.test(password)) {
callback(new Error('密码不能包含3个连续或相同的数字(正序或逆序)!'));
}
// 规则5:不能包含3个连续或相同的字母(不区分大小写,正序/逆序)
// 构建连续字母正序和逆序正则(a-z 和 z-a,不区分大小写)
const lowerPwd = password.toLowerCase();
// 正序连续三个字母如 abc, bcd, ..., xyz
for (let i = 0; i <= 23; i++) {
const a = String.fromCharCode(97 + i);
const b = String.fromCharCode(97 + i + 1);
const c = String.fromCharCode(97 + i + 2);
const seq = a + b + c;
if (lowerPwd.includes(seq)) {
callback(new Error('密码不能包含3个连续的字母(正序或逆序)!'));
}
}
// 逆序连续三个字母如 cba, bcd -> 这里只考虑逆序如 cba (即 z-a方向)
for (let i = 0; i <= 23; i++) {
const a = String.fromCharCode(97 + i + 2);
const b = String.fromCharCode(97 + i + 1);
const c = String.fromCharCode(97 + i);
const seq = a + b + c;
if (lowerPwd.includes(seq)) {
callback(new Error('密码不能包含3个连续的字母(正序或逆序)!'));
}
}
// 检查3个相同的字母(不区分大小写)
const sameLetterRegex = /(.)\1{2}/; // 任意字符连续出现3次
if (sameLetterRegex.test(lowerPwd)) {
callback(new Error('密码不能包含3个相同的字母(不区分大小写)!'));
}
// 所有规则通过
callback();
}