密码强度校验
前言:在前端开发过程中,登录注册页面几乎都是必不可少的页面,有些产品经理就会要求我们对密码进行强度的校验,普通的长度校验很简单,使用正则就可以实现,但是如果需要使用绿、黄、红色来提示用户,又怎么来做呢?废话不多说,直接上代码
校验规则
CheckPassword.js/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 密码
*/
export function checkPasswordRule(password: string) {
if (password === '' || password.length < 8 || password.length > 16) {
// console.log("长度小于8,或大于16");
return '密码长度应大于8小于16'
}
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 < 3) {
// console.log(("数字、小写字母、大写字母、特殊字符,至少包含两种"));
return '数字、小写字母、大写字母、特殊字符,至少包含三种'
}
// console.log(i);
return '校验通过'
}
/**
* 是否包含3个及以上相同或字典连续字符
*/
function isContinuousChar(password: string) {
const chars: string[] = password.split('')
const 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++) {
const n1 = charCode[i]
const n2 = charCode[i + 1]
const 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 待匹配的字符串
*/
function isKeyBoardContinuousChar(password: string) {
if (password === '')
return false
// 考虑大小写,都转换成小写字母
const lpStrChars: string[] = password.toLowerCase().split('')
// 获取字符串长度
const nStrLen: number = lpStrChars.length
// 定义位置数组:row - 行,col - column 列
const pRowCharPos: number[] = Array.from({ length: nStrLen }).fill('')
const pColCharPos: number[] = Array.from({ length: nStrLen }).fill('')
for (let i = 0; i < nStrLen; i++) {
const 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
*/
function length(str: string) {
if (str.length < 8)
return 5
else if (str.length < 12)
return 10
else
return 25
}
/**
* 字母
* @param str
*/
function letters(str: string) {
let count1 = 0
let 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
*/
function 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
*/
function 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
*/
function rewards(str: string) {
const letter = letters(str)// 字母
const number = numbers(str)// 数字
const 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 function level(str: string) {
const lengths = length(str)// 长度
const letter = letters(str)// 字母
const number = numbers(str)// 数字
const symbol = symbols(str)// 符号
const reward = rewards(str)// 奖励
const 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 '非常弱'// 非常弱
}
登录页使用
login.vue
script
<script setup lang="ts"> // 强度条颜色 const barColor = ref('') // 强度条长度 const width = ref('') const showStrong = ref(false) // 强度条文字描述 const strength = ref('') x function handlePasswordCheck(val: string) { // 可以根据自己需要调整下边的颜色、描述及长度 const res: string = level(val) // 必须通过校验再显示其他颜色 if (checkPasswordRule(val) === '密码长度应大于8小于16' || checkPasswordRule(val) === '数字、小写字母、大写字母、特殊字符,至少包含三种') { barColor.value = 'red' strength.value = '非常弱' width.value = '30' return } if (res === '非常弱') { barColor.value = 'red' strength.value = '非常弱' width.value = '30' } else if (res === '一般' && checkPasswordRule(val)) { barColor.value = 'yellow' strength.value = '一般' width.value = '60' } else if (res === '强') { barColor.value = 'green' strength.value = '强' width.value = '100' } } </scrpit>
template
<template> <el-form-item label="密码" prop="password"> <el-input v-model.trim="registeredForm.password" type="password" placeholder="请输入密码" @blur="showStrong = false" @focus="showStrong = true" /> <!-- 展示长度条 --> <div v-if="registeredForm.password !== '' && registeredForm.password !== undefined && showStrong" class="bar" :style="{ background: barColor, width: `${width}%` }" > <!-- 展示文字 --> <div v-if="registeredForm.password !== '' && registeredForm.password !== undefined" class="strength" :style="{ color: barColor }" > {{ strength }} </div> </div> </el-form-item> </template>
style
<style scoped lang="scss"> .strength { font-size: 13px; color: #271E25; position: relative; top: 0; 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; top: 60px; } </style>
评论
0 评论