一、效果描述和结果展示:
- 密码强弱 校验是根据以下四种规则来判断划分的5个等级。
- 长度
- 字母
- 数字
- 符号
- 密码规则 校验是根据以下四种规则来进行校验。
- 是否包含用户名;
- 是否包含3个及以上相同或连续的字符;
- 是否包含3个及以上键盘连续字符;(横向、斜向都包括)
- 数字、小写字母、大写字母、特殊字符,至少包含两种
结果展示:
- 密码长度小于8 位
- 密码包含用户名
- 密码包含3个相同或者连续的字符
- 包含3个及以上键盘连续字符;(横向、斜向都包括)
- 密码不满足数字、小写字母、大写字母、特殊字符,至少包含两种
- 各项密码强度展示
二、静态页面:
<el-form
:model="registerData"
label-width="100px"
:rules="rules"
ref="ruleFormRef">
<el-form-item label="密码" prop="password">
<el-input v-model="registerData.password" placeholder="请输入密码" />
</el-form-item>
<el-form-item
v-if="registerData.password !== '' && registerData.password !== undefined"
label=""
align="center"
style="height: 25px">
<!-- 展示长度条 -->
<div
class="bar"
v-if="registerData.password !== '' && registerData.password !== undefined"
:style="{ background: barColor, width: width + '%' }">
<!-- 展示文字 -->
<div
class="strength"
:style="{ color: barColor }"
v-if="registerData.password !== '' && registerData.password !== undefined">
{{ strength }}
</div>
</div>
</el-form-item>
</el-form>
三、css部分:
.strength {
font-size: 13px;
color: #271E25;
position: relative;
top: 5px;
left: 0;
transition: 0.5s all ease;
}
.bar {
/* width: 400px; */
height: 5px;
background: red;
transition: 0.5s all ease;
max-width: 420px;
margin: 2px 0 5px 5px;
position: absolute;
}
四、ts部分:
import { ref, watch, reactive } from 'vue';
import type { FormInstance } from 'element-plus';
// 引入验证方法
import { checkPasswordRule, level } from './CheckPassword';
// 强度条颜色
const barColor = ref('');
// 强度条长度
const width = ref('');
// 强度条说明
const strength = ref('');
const ruleFormRef = ref<FormInstance>();
// 注册表单校验规则
const rules = reactive({
password: [{ validator: validatePassword, trigger: 'blur' }]
});
// 注册数据
const registerData = reactive({
password: '',
});
// 监听注册页面的新密码变化状态,来改变密码强弱显示
watch(
() => registerData.password,
(newVal) => {
if (newVal != '') {
const res: string = level(newVal);
if (res == '非常弱') {
barColor.value = 'red';
width.value = '20';
strength.value = '非常弱';
} else if (res == '弱') {
barColor.value = '#ee795c';
width.value = '40';
strength.value = '弱';
} else if (res == '一般') {
barColor.value = 'orange';
width.value = '60';
strength.value = '一般';
} else if (res == '强') {
barColor.value = 'green';
width.value = '80';
strength.value = '强';
} else if (res == '非常强') {
barColor.value = '#1B8EF8';
width.value = '100';
strength.value = '非常强';
}
}
}
);
// 密码校验规则
const validatePassword = (rule: any, value: string, callback: any) => {
if (value === '') {
callback(new Error('请输入密码'));
} else {
let name: string = '';
if (registerData.username === '') {
name = '空';
} else {
name = registerData.username;
}
const result: string = checkPasswordRule(value, name);
if (result === '校验通过') {
callback();
} else {
callback(new Error(result));
}
}
};
// 提交校验方法
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate((valid) => {
if (valid) {
console.log('submit!');
ElMessage({
message: '注册成功!',
type: 'success'
});
} else {
console.log('error submit!');
return false;
}
});
};
五、强弱校验、规则校验 CheckPassword.ts:
/**
* 数字
*/
const REG_NUMBER:string = ".*\\d+.*";
/**
* 小写字母
*/
const REG_UPPERCASE:string = ".*[A-Z]+.*";
/**
* 大写字母
*/
const REG_LOWERCASE:string = ".*[a-z]+.*";
/**
* 特殊符号(~!@#$%^&*()_+|<>,.?/:;'[]{}\)
*/
const REG_SYMBOL:string = ".*[~!@#$%^&*()_+|<>,.?/:;'\\[\\]{}\"]+.*";
/**
* 键盘字符表(小写)
* 非shift键盘字符表
*/
const CHAR_TABLE1:string[][] = [
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\0'],
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\'],
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '\0', '\0'],
['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '\0', '\0', '\0']];
/**
* shift键盘的字符表
*/
const CHAR_TABLE2:string[][] = [
['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\0'],
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '{', '}', '|'],
['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ':', '"', '\0', '\0'],
['z', 'x', 'c', 'v', 'b', 'n', 'm', '<', '>', '?', '\0', '\0', '\0']];
/**
* 校验密码是否符合条件
* @param password 密码
* @param username 用户名
*/
export const checkPasswordRule = (password:string,username:string) => {
if (password === '' || password.length < 8 || password.length > 32) {
// console.log("长度小于8,或大于32");
return "密码长度应大于8小于32";
} if (password.indexOf(username) !== -1) {
// console.log("包含用户名");
return "请勿包含用户名";
}
if (isContinuousChar(password)) {
// console.log("包含3个及以上相同或字典连续字符");
return "请勿包含3个及以上相同或连续的字符";
}
if (isKeyBoardContinuousChar(password)) {
// console.log("包含3个及以上键盘连续字符");
return "请勿包含3个及以上键盘连续字符";
}
let i:number = 0;
if (password.match(REG_NUMBER)) i++;
if (password.match(REG_LOWERCASE)) i++;
if (password.match(REG_UPPERCASE)) i++;
if (password.match(REG_SYMBOL)) i++;
if (i < 2) {
// console.log(("数字、小写字母、大写字母、特殊字符,至少包含两种"));
return "数字、小写字母、大写字母、特殊字符,至少包含两种";
}
// console.log(i);
return "校验通过";
}
/**
* 是否包含3个及以上相同或字典连续字符
*/
const isContinuousChar = (password:string) => {
let chars: string[] = password.split('')
let charCode: number[] = [];
for (let i = 0; i < chars.length - 2; i++) {
charCode[i] = chars[i].charCodeAt(0)
}
for (let i = 0; i < charCode.length - 2; i++) {
let n1 = charCode[i];
let n2 = charCode[i + 1];
let n3 = charCode[i + 2];
// 判断重复字符
if (n1 == n2 && n1 == n3) {
return true;
}
// 判断连续字符: 正序 + 倒序
if ((n1 + 1 == n2 && n1 + 2 == n3) || (n1 - 1 == n2 && n1 - 2 == n3)) {
return true;
}
}
return false;
}
/**
* 是否包含3个及以上键盘连续字符
* @param password 待匹配的字符串
*/
const isKeyBoardContinuousChar = (password:string) => {
if (password === '') {
return false;
}
//考虑大小写,都转换成小写字母
let lpStrChars: string[] = password.toLowerCase().split('')
// 获取字符串长度
let nStrLen: number = lpStrChars.length;
// 定义位置数组:row - 行,col - column 列
const pRowCharPos:number[] = new Array(nStrLen).fill('')
const pColCharPos: number[] = new Array(nStrLen).fill('')
for (let i = 0; i < nStrLen; i++) {
let chLower: string = lpStrChars[i];
pColCharPos[i] = -1;
// 检索在表1中的位置,构建位置数组
for (let nRowTable1Idx = 0; nRowTable1Idx < 4; nRowTable1Idx++) {
for (let nColTable1Idx = 0; nColTable1Idx < 13; nColTable1Idx++) {
if (chLower == CHAR_TABLE1[nRowTable1Idx][nColTable1Idx]) {
pRowCharPos[i] = nRowTable1Idx;
pColCharPos[i] = nColTable1Idx;
}
}
}
// 在表1中没找到,到表二中去找,找到则continue
if (pColCharPos[i] >= 0) {
continue;
}
// 检索在表2中的位置,构建位置数组
for (let nRowTable2Idx = 0; nRowTable2Idx < 4; nRowTable2Idx++) {
for (let nColTable2Idx = 0; nColTable2Idx < 13; nColTable2Idx++) {
if (chLower == CHAR_TABLE2[nRowTable2Idx][nColTable2Idx]) {
pRowCharPos[i] = nRowTable2Idx;
pColCharPos[i] = nColTable2Idx;
}
}
}
}
// 匹配坐标连线
for (let j = 1; j <= nStrLen - 2; j++) {
//同一行
if (pRowCharPos[j - 1] == pRowCharPos[j] && pRowCharPos[j] == pRowCharPos[j + 1]) {
// 键盘行正向连续(asd)或者键盘行反向连续(dsa)
if ((pColCharPos[j - 1] + 1 == pColCharPos[j] && pColCharPos[j] + 1 == pColCharPos[j + 1]) ||
(pColCharPos[j + 1] + 1 == pColCharPos[j] && pColCharPos[j] + 1 == pColCharPos[j - 1])) {
return true;
}
}
//同一列
if (pColCharPos[j - 1] == pColCharPos[j] && pColCharPos[j] == pColCharPos[j + 1]) {
//键盘列连续(qaz)或者键盘列反向连续(zaq)
if ((pRowCharPos[j - 1] + 1 == pRowCharPos[j] && pRowCharPos[j] + 1 == pRowCharPos[j + 1]) ||
(pRowCharPos[j - 1] - 1 == pRowCharPos[j] && pRowCharPos[j] - 1 == pRowCharPos[j + 1])) {
return true;
}
}
}
return false;
}
/**
* 密码强度校验
*/
/**
* 长度
* @param str
*/
const length = (str:string) => {
if(str.length<5){
return 5;
}else if(str.length<8){
return 10;
}else{
return 25;
}
}
/**
* 字母
* @param str
*/
const letters = (str: string) => {
let count1=0,count2=0;
for(let i=0;i<str.length;i++){
if(str.charAt(i)>='a'&&str.charAt(i)<='z'){
count1++;
}
if(str.charAt(i)>='A'&&str.charAt(i)<='Z'){
count2++;
}
}
if(count1==0 && count2==0){
return 0;
}
if(count1!=0 && count2!=0){
return 20;
}
return 10;
}
/**
* 数字
* @param str
*/
const numbers = (str: string) => {
let count=0;
for(let i=0;i<str.length;i++){
if(str.charAt(i)>='0'&&str.charAt(i)<='9'){
count++;
}
}
if(count==0){
return 0;
}
if(count==1){
return 10;
}
return 20;
}
/**
* 符号
* @param str
*/
const symbols = (str: string) => {
let count=0;
for(let i=0;i<str.length;i++){
if(str.charCodeAt(i)>=0x21 && str.charCodeAt(i)<=0x2F ||
str.charCodeAt(i)>=0x3A && str.charCodeAt(i)<=0x40 ||
str.charCodeAt(i)>=0x5B && str.charCodeAt(i)<=0x60 ||
str.charCodeAt(i)>=0x7B && str.charCodeAt(i)<=0x7E ){
count++;
}
}
if(count==0){
return 0;
}
if(count==1){
return 10;
}
return 25;
}
/**
* 得分机制
* @param str
*/
const rewards = (str: string) => {
let letter=letters(str);//字母
let number=numbers(str);//数字
let symbol=symbols(str);//符号
if(letter>0 && number>0 && symbol==0){//字母和数字
return 2;
}
if(letter==10 && number>0 && symbol>0){//字母、数字和符号
return 3;
}
if(letter==20 && number>0 && symbol>0){//大小写字母、数字和符号
return 5;
}
return 0;
}
/**
* 最终评分
* @param str
*/
export const level = (str: string) => {
let lengths=length(str);//长度
let letter=letters(str);//字母
let number=numbers(str);//数字
let symbol=symbols(str);//符号
let reward=rewards(str);//奖励
let sum=lengths+letter+number+symbol+reward;
console.log(sum);
if(sum>=80){
return "非常强";//非常安全
}else if(sum>=60){
return "强";//非常强
}else if(sum>=40){
return "一般";//一般
}else if(sum>=25){
return "弱";//弱
}else{
return "非常弱";//非常弱
}
}