本文目录
- 前言
- 功能预览
- 样式特点总结:
-
- [1. 整体视觉风格](#1. 整体视觉风格)
- [2. 密码输入框设计](#2. 密码输入框设计)
- [3. 强度指示条](#3. 强度指示条)
- [4. 结果文本与原因说明](#4. 结果文本与原因说明)
- 功能特点总结:
-
- [1. 密码强度检测](#1. 密码强度检测)
- [2. 实时反馈机制](#2. 实时反馈机制)
- [3. 详细原因说明](#3. 详细原因说明)
- [4. 视觉提示](#4. 视觉提示)
- [5. 交互体验优化](#5. 交互体验优化)
- 密码强度检测逻辑总
- Html代码
- Javascript代码
前言
能满足等级保护测评要求的基本功能都实现了,可能还存在部分功能没有添加,密码强度验证逻辑可能还有需要强化的地方,有问题欢迎评论区讨论~
功能预览


样式特点总结:
1. 整体视觉风格
- 使用深色主题背景,搭配线性渐变(从
#141E30
到#243B55
),营造专业且现代的视觉效果。 - 容器使用半透明黑色背景(
rgba(0, 0, 0, 0.6)
),边缘带有圆角(border-radius: 15px
)和阴影效果(box-shadow
),提升界面的层次感。
2. 密码输入框设计
- 输入框采用无边框设计,背景色为浅灰色(
rgba(255, 255, 255, 0.1)
),聚焦时背景色变深(rgba(255, 255, 255, 0.2)
),提供良好的交互反馈。 - 输入框字体大小适中(
font-size: 16px
),占满容器宽度(width: 100%
),确保良好的可用性。
3. 强度指示条
- 强度指示条由三个彩色块组成(红色
#FF4136
、黄色#FFDC00
、绿色#2ECC40
),每个块的高度固定(height: 10px
),宽度随强度变化。 - 使用过渡效果(
transition: width 0.3s ease
)使颜色块变化平滑。 - 未激活的块设置为低透明度(
.hidden { opacity: 0.2; }
),增强视觉层次。
4. 结果文本与原因说明
- 结果文字根据强度不同显示不同颜色(弱:红色;中:黄色;强:绿色)。
- 原因说明部分使用无序列表展示具体原因,左侧带有项目符号(
list-style-type: disc
),排版清晰易读。
功能特点总结:
1. 密码强度检测
- 检测密码的长度(最低要求 8 位)、字符类型(大写/小写字母、数字、特殊字符)以及是否存在安全隐患(如连续数字、重复字符、键盘规律等)。
- 提供三种强度评级:弱(Weak)、中(Medium)、强(Strong),并实时更新结果。
2. 实时反馈机制
- 在用户输入过程中,实时检测密码强度并更新界面显示。
- 当密码为空时,提示用户"请输入密码"。
3. 详细原因说明
- 对于强度较弱或中等的密码,显示具体原因(如"密码长度不足8位"、"包含连续数字"等),帮助用户改进密码。
4. 视觉提示
- 使用颜色块动态展示密码强度,直观明了。
- 不同强度对应不同的颜色和提示信息,便于用户快速理解结果。
5. 交互体验优化
- 输入框聚焦时背景色变化,提供良好的交互反馈。
- 原因说明部分使用无序列表,排版清晰,易于阅读。
密码强度检测逻辑总
这个密码强度检测工具的核心逻辑主要集中在 checkPasswordStrength
函数中。以下是详细的逻辑总结:
- 基础条件检测
密码强度检测基于以下基础条件:
- 密码长度:密码长度必须至少为 8 位。
- 字符类型:密码必须包含以下至少两种字符类型:
- 大写字母(A-Z)
- 小写字母(a-z)
- 数字(0-9)
- 特殊字符(非字母数字字符)
- 安全性检查
密码强度检测还包括以下安全性检查:
- 连续数字:检测密码中是否包含连续的数字序列(例如
123
、456
等)。 - 重复字符:检测密码中是否存在重复的字符(例如
aa
、bb
等)。 - 键盘规律:检测密码是否符合常见的键盘输入规律(例如
qwe
、123
、asdf
等)。 - 跨行键盘规律:检测密码是否符合跨行键盘输入规律(例如
qaz
、wsx
等)。
-
强度评级规则
根据上述条件,密码强度分为以下三个等级:
-
弱(Weak):
- 密码长度不足 8 位。
- 密码仅包含两种或更少字符类型。
- 密码存在连续数字、重复字符或符合键盘输入规律。
- 密码缺少特殊字符。
-
中(Medium):
- 密码长度达到 8 位以上。
- 密码包含三种字符类型。
- 密码不存在明显的安全风险(如连续数字、重复字符或键盘规律)。
-
强(Strong):
- 密码长度达到 8 位以上。
- 密码包含四种字符类型(大写字母、小写字母、数字、特殊字符)。
- 密码不存在连续数字、重复字符或键盘规律。
-
详细逻辑流程
以下是
checkPasswordStrength
函数的详细逻辑流程: -
初始检查:
- 如果密码为空,返回"请输入密码"的提示信息。
-
字符类型检测:
- 检查密码是否包含大写字母、小写字母、数字和特殊字符,并记录包含的字符类型。
-
安全性检查:
- 使用正则表达式检测密码中是否存在连续数字(
SEQUENTIAL_NUMBER_REGEX
)。 - 使用正则表达式检测密码中是否存在重复字符(
REPEATED_CHARS_REGEX
)。 - 使用正则表达式检测密码中是否存在键盘规律(
KEYBOARD_REGEX
)。 - 检查密码是否符合跨行键盘规律(通过
keyboardLayoutIndexes
和keyboardLayout
实现)。
- 使用正则表达式检测密码中是否存在连续数字(
-
强度评级:
- 如果密码长度不足 8 位或存在明显安全风险(如连续数字、重复字符或键盘规律),评级为"弱"。
- 如果密码包含三种字符类型且不存在明显安全风险,评级为"中"。
- 如果密码包含四种字符类型且不存在任何安全风险,评级为"强"。
-
结果反馈:
- 返回密码强度评级和具体原因(例如"密码强度:弱"、"密码长度不足8位"等)。
Html代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>密码强度检测</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
background: linear-gradient(to bottom right, #141E30, #243B55);
color: #e0e0e0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background-color: rgba(0, 0, 0, 0.6);
padding: 40px;
border-radius: 15px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
width: 400px;
}
h1 {
color: #e0e0e0;
text-align: center;
margin-bottom: 30px;
font-size: 28px;
}
/* 密码输入框样式 */
.password-input {
width: 100%;
padding: 15px;
margin-bottom: 20px;
border: none;
border-radius: 8px;
box-sizing: border-box;
background-color: rgba(255, 255, 255, 0.1);
color: #e0e0e0;
font-size: 16px;
outline: none;
transition: background-color 0.3s ease;
}
.password-input:focus {
background-color: rgba(255, 255, 255, 0.2);
}
.strength-meter {
height: 10px;
width: 100%;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
margin-bottom: 20px;
overflow: hidden;
display: flex;
}
.strength-bar {
height: 100%;
transition: width 0.3s ease, background-color 0.3s ease;
width: 33.33%;
}
.strength-bar:nth-child(1) {
background-color: #FF4136;
}
.strength-bar:nth-child(2) {
background-color: #FFDC00;
}
.strength-bar:nth-child(3) {
background-color: #2ECC40;
}
.strength-bar.hidden {
opacity: 0.2;
}
.result-text {
margin-bottom: 10px;
font-weight: bold;
font-size: 18px;
text-align: center;
}
.weak-text {
color: #FF4136;
}
.medium-text {
color: #FFDC00;
}
.strong-text {
color: #2ECC40;
}
.reasons {
margin-top: 20px;
}
.reasons p {
margin-bottom: 10px;
font-size: 16px;
}
.reasons ul {
list-style-type: disc;
padding-left: 20px;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<h1>密码强度检测</h1>
<input type="password" class="password-input" placeholder="请输入密码">
<div class="strength-meter">
<div class="strength-bar hidden"></div>
<div class="strength-bar hidden"></div>
<div class="strength-bar hidden"></div>
</div>
<div class="result-text"></div>
<div class="reasons"></div>
</div>
</body>
</html>
Javascript代码
javascript
<script>
const passwordInput = document.querySelector('.password-input');
const strengthBars = document.querySelectorAll('.strength-bar');
const resultText = document.querySelector('.result-text');
const reasonsDiv = document.querySelector('.reasons');
const MIN_PASSWORD_LENGTH = 8;
const SEQUENTIAL_NUMBER_REGEX = /(?:012|123|234|345|456|567|678|789|987|876|765|654|543|432|321|210)/;
const REPEATED_CHARS_REGEX = /([a-zA-Z])\1/i;
const keyboardLayout = [
'`1234567890-=',
'qwertyuiop[]\\',
'asdfghjkl;\'',
'zxcvbnm,./'
].join('');
const keyboardLayoutIndexes = {};
for (let i = 0; i < keyboardLayout.length; i++) {
keyboardLayoutIndexes[keyboardLayout[i]] = i;
}
// 键盘规律正则表达式
const keyboardPatterns = [
// 单行规律
'qwe', 'wer', 'ert', 'rty', 'tyu', 'yui', 'uio', 'iou',
'asd', 'sdf', 'dfg', 'fgh', 'ghj', 'hjk', 'jkl',
'zxc', 'xcv', 'cvb', 'vbn',
// 符号键盘
'!@#', '@#$', '#$%', '$%^', '%^&', '^&*', '&*(',
'!qwe', '@wsx', '#edc', '$rfv', '%tgb', '^yhn', '&ujm', '*k,',
// 数字键盘
'123', '234', '345', '456', '567', '678', '789',
'987', '876', '765', '654', '543', '432', '321',
'147', '258', '369',
// 跨行规律
'qaz', 'wsx', 'edc', 'rfv', 'tgb', 'yhn', 'ujm', 'k\\.,',
'QAZ', 'WSX', 'EDC', 'RFV', 'TGB', 'YHN', 'UJM', 'K\\.,',
// 符号+字母跨行
'!qaz', '@wsx', '#edc', '$rfv', '%tgb', '^yhn', '&ujm', '*k,',
'!QAZ', '@WSX', '#EDC', '$RFV', '%TGB', '^YHN', '&UJM', '*K,',
// 数字+字母跨行
'1qaz', '2wsx', '3edc', '4rfv', '5tgb', '6yhn', '7ujm', '8k,',
'1QAZ', '2WSX', '3EDC', '4RFV', '5TGB', '6YHN', '7UJM', '8K.',
// 添加大小写混合的情况
'1QaZ', '2WsX', '3EdC', '4RfV', '5TgB', '6YhN', '7UjM', '8K.',
'!QaZ', '@WsX', '#EdC', '$RfV', '%TgB', '^YhN', '&UjM', '*K,'
];
const regexPatterns = keyboardPatterns.map(pattern => pattern.replace(/([.*+?^${}() |[\]\\])/g, '\\$1'));
const KEYBOARD_REGEX = new RegExp(regexPatterns.join('|'), 'i');
function checkPasswordStrength(password) {
if (!password) {
return { strength: 'empty', reasons: ['请输入密码'] };
}
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecialChars = /[^a-zA-Z\d]/.test(password);
const charTypes = [];
if (hasUpperCase) charTypes.push(' 大写字母');
if (hasLowerCase) charTypes.push(' 小写字母');
if (hasNumbers) charTypes.push(' 数字');
if (hasSpecialChars) charTypes.push(' 特殊字符');
const hasSequentialNumbers = SEQUENTIAL_NUMBER_REGEX.test(password);
const hasRepeatedChars = REPEATED_CHARS_REGEX.test(password);
const hasKeyboardPattern = KEYBOARD_REGEX.test(password);
function hasSequentialKeyboardKeys(password) {
for (let i = 0; i < password.length - 2; i++) {
const charIndex = keyboardLayoutIndexes[password[i].toLowerCase()];
const nextIndex = keyboardLayoutIndexes[password[i + 1].toLowerCase()];
const nextNextIndex = keyboardLayoutIndexes[password[i + 2].toLowerCase()];
if (nextIndex === charIndex + 1 && nextNextIndex === nextIndex + 1) {
return true;
}
}
return false;
}
const reasons = [];
if (password.length < MIN_PASSWORD_LENGTH) {
reasons.push(' 密码长度不足8位');
}
if (hasSequentialNumbers) {
reasons.push(' 包含连续数字');
}
if (hasRepeatedChars) {
reasons.push(' 包含重复字符');
}
if (hasKeyboardPattern || hasSequentialKeyboardKeys(password)) {
reasons.push(' 符合键盘输入规律');
}
if (!hasSpecialChars) {
reasons.push(' 缺少特殊字符');
}
let strength;
if (
(charTypes.length <= 2 && password.length >= MIN_PASSWORD_LENGTH) ||
reasons.length > 1 ||
hasSequentialKeyboardKeys(password)
) {
strength = 'weak';
reasons.unshift(' 密码强度:弱');
} else if (
charTypes.length === 4 &&
!hasKeyboardPattern &&
!hasSequentialNumbers &&
!hasRepeatedChars &&
!hasSequentialKeyboardKeys(password)
) {
strength = 'strong';
reasons.unshift(' 密码强度:强');
} else {
strength = 'medium';
reasons.unshift(' 密码强度:中');
}
return { strength, reasons };
}
document.addEventListener('input', function (event) {
if (event.target === passwordInput) {
const result = checkPasswordStrength(event.target.value);
strengthBars.forEach((bar, index) => {
if (result.strength === 'weak') {
if (index === 0) {
bar.classList.remove('hidden');
} else {
bar.classList.add('hidden');
}
} else if (result.strength === 'medium') {
if (index < 2) {
bar.classList.remove('hidden');
} else {
bar.classList.add('hidden');
}
} else if (result.strength === 'strong') {
bar.classList.remove('hidden');
} else {
bar.classList.add('hidden');
}
});
if (result.strength === 'empty') {
resultText.innerHTML = '';
reasonsDiv.innerHTML = '';
return;
}
resultText.className = `${result.strength}-text`;
resultText.innerHTML = result.reasons[0];
if (result.strength === 'weak' || result.strength === 'medium') {
reasonsDiv.innerHTML = `
<p>原因:</p>
<ul>${result.reasons.slice(1).map(r => `<li>${r}</li>`).join('')}</ul>
`;
} else {
reasonsDiv.innerHTML = '';
}
}
});
</script>