源本科技 | 码上会

随机密码生成器

2026/01/13
10
0

学习目标

  • 掌握字符集拼接随机索引选择的密码生成逻辑

  • 实现基于用户偏好的动态字符池构建(大小写、数字、特殊符号)

  • 理解密码安全性与字符多样性的关系

  • 构建一个具备良好用户体验的交互式前端工具

  • 学会使用现代 CSS 技术(如 Flexbox、透明背景、渐变)美化界面


密码安全基础

一个强密码应具备以下特征:

特性

说明

长度 ≥ 8 位

越长越难暴力破解(推荐 12+ 位)

包含大小写字母

增加字符空间(26 → 52 个字母)

包含数字

引入 10 个额外字符

包含特殊符号

!@#$%,大幅提升组合复杂度

无规律可循

避免使用字典词、生日、连续数字等

本项目默认启用所有选项,符合 NIST(美国国家标准与技术研究院)对强密码的建议。


应用功能设计

我们将实现一个可定制化密码生成器,支持:

  • 设置密码长度(默认 12,最小 6)

  • 勾选是否包含:

    • 大写字母(A–Z)

    • 数字(0–9)

    • 特殊字符(如 !@#$%^&*

  • 一键生成符合要求的随机密码

  • “重置”按钮恢复默认配置

  • 结果区域自动换行,便于复制


HTML 结构

<div class="container">
  <h1>密码生成器</h1>
  
  <label>
    密码长度:
    <input id="len" type="number" min="6" max="128" value="12" />
  </label>
  
  <label>
    <input id="upper" type="checkbox" checked /> 包含大写字母
  </label>
  
  <label>
    <input id="nums" type="checkbox" checked /> 包含数字
  </label>
  
  <label>
    <input id="special" type="checkbox" checked /> 包含特殊字符
  </label>
  
  <button class="btn" id="generateBtn">生成密码</button>
  <button class="btn" id="resetBtn">重置</button>
  
  <div class="output" id="passOut">您的密码将在此显示</div>
</div>

设计说明:

  • 使用 <label> 包裹 <input>:提升点击区域,改善移动端体验

  • 限制 max="128":防止生成过长密码导致性能问题

  • 默认全选:鼓励用户生成高强度密码


CSS 样式

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
  color: white;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  margin: 0;
  padding: 20px;
}

.container {
  background: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(10px); /* 毛玻璃效果(现代浏览器支持) */
  padding: 28px;
  border-radius: 16px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
  text-align: center;
  width: 100%;
  max-width: 380px;
}

h1 {
  font-size: 26px;
  font-weight: 700;
  margin-bottom: 24px;
  letter-spacing: 0.5px;
}

label {
  display: block;
  margin: 14px 0;
  font-size: 16px;
  font-weight: 500;
}

input[type="number"] {
  width: 60px;
  padding: 6px 10px;
  border: none;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.2);
  color: white;
  text-align: center;
  font-size: 16px;
}

input[type="checkbox"] {
  transform: scale(1.2);
  margin-right: 8px;
  accent-color: #ffd700; /* 自定义复选框颜色 */
}

.output {
  margin: 24px 0;
  padding: 16px;
  font-size: 18px;
  font-family: monospace;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 10px;
  word-break: break-all;
  min-height: 28px;
  line-height: 1.4;
}

.btn {
  background: #ff6b6b;
  color: white;
  border: none;
  padding: 12px 24px;
  margin: 8px 6px;
  border-radius: 10px;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.25s ease;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
}

#resetBtn {
  background: #4ecdc4;
}

视觉亮点:

  • 毛玻璃效果backdrop-filter: blur()):提升现代感

  • 自定义复选框颜色:更符合主题色

  • 等宽字体显示密码:便于区分 0/O1/l 等易混淆字符

  • 悬停动效:增强交互反馈


JavaScript 逻辑

// 字符集定义
const LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
const UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const NUMBERS = "0123456789";
const SPECIAL = "!@#$%^&*()-_=+[]{}|;:,.<>?";

// 生成密码函数
function generatePassword(length, includeUpper, includeNumbers, includeSpecial) {
  if (length < 1) return "";

  let charPool = LOWERCASE;

  if (includeUpper) charPool += UPPERCASE;
  if (includeNumbers) charPool += NUMBERS;
  if (includeSpecial) charPool += SPECIAL;

  // 安全检查:确保字符池非空
  if (charPool.length === 0) {
    alert("请至少选择一种字符类型!");
    return "";
  }

  let password = "";
  for (let i = 0; i < length; i++) {
    const randomIndex = Math.floor(Math.random() * charPool.length);
    password += charPool[randomIndex];
  }

  return password;
}

// DOM 元素获取
const lenInput = document.getElementById('len');
const upperCheckbox = document.getElementById('upper');
const numsCheckbox = document.getElementById('nums');
const specialCheckbox = document.getElementById('special');
const generateBtn = document.getElementById('generateBtn');
const resetBtn = document.getElementById('resetBtn');
const outputDiv = document.getElementById('passOut');

// 生成密码并显示
function handleGenerate() {
  const length = parseInt(lenInput.value, 10);

  if (isNaN(length) || length < 6) {
    outputDiv.textContent = "长度至少为 6 位";
    return;
  }

  const password = generatePassword(
    length,
    upperCheckbox.checked,
    numsCheckbox.checked,
    specialCheckbox.checked
  );

  if (password) {
    outputDiv.textContent = password;
  }
}

// 重置表单
function handleReset() {
  lenInput.value = 12;
  upperCheckbox.checked = true;
  numsCheckbox.checked = true;
  specialCheckbox.checked = true;
  outputDiv.textContent = "您的密码将在此显示";
}

// 绑定事件(避免内联 onclick)
generateBtn.addEventListener('click', handleGenerate);
resetBtn.addEventListener('click', handleReset);

// 支持回车键快速生成
document.addEventListener('keypress', (e) => {
  if (e.key === 'Enter') handleGenerate();
});

完整代码整合

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>随机密码生成器</title>
  <style>
    /* 此处插入上方优化后的 CSS */
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);
      color: white;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      margin: 0;
      padding: 20px;
    }
    .container {
      background: rgba(255, 255, 255, 0.12);
      backdrop-filter: blur(10px);
      padding: 28px;
      border-radius: 16px;
      box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25);
      text-align: center;
      width: 100%;
      max-width: 380px;
    }
    h1 {
      font-size: 26px;
      font-weight: 700;
      margin-bottom: 24px;
      letter-spacing: 0.5px;
    }
    label {
      display: block;
      margin: 14px 0;
      font-size: 16px;
      font-weight: 500;
    }
    input[type="number"] {
      width: 60px;
      padding: 6px 10px;
      border: none;
      border-radius: 6px;
      background: rgba(255, 255, 255, 0.2);
      color: white;
      text-align: center;
      font-size: 16px;
    }
    input[type="checkbox"] {
      transform: scale(1.2);
      margin-right: 8px;
      accent-color: #ffd700;
    }
    .output {
      margin: 24px 0;
      padding: 16px;
      font-size: 18px;
      font-family: monospace;
      background: rgba(0, 0, 0, 0.2);
      border-radius: 10px;
      word-break: break-all;
      min-height: 28px;
      line-height: 1.4;
    }
    .btn {
      background: #ff6b6b;
      color: white;
      border: none;
      padding: 12px 24px;
      margin: 8px 6px;
      border-radius: 10px;
      font-size: 16px;
      font-weight: 600;
      cursor: pointer;
      transition: all 0.25s ease;
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
    }
    .btn:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
    }
    #resetBtn {
      background: #4ecdc4;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>随机密码生成器</h1>
    
    <label>
      密码长度:
      <input id="len" type="number" min="6" max="128" value="12" />
    </label>
    
    <label>
      <input id="upper" type="checkbox" checked /> 包含大写字母
    </label>
    
    <label>
      <input id="nums" type="checkbox" checked /> 包含数字
    </label>
    
    <label>
      <input id="special" type="checkbox" checked /> 包含特殊字符
    </label>
    
    <button class="btn" id="generateBtn">生成密码</button>
    <button class="btn" id="resetBtn">重置</button>
    
    <div class="output" id="passOut">您的密码将在此显示</div>
  </div>

  <script>
    const LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
    const UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    const NUMBERS = "0123456789";
    const SPECIAL = "!@#$%^&*()-_=+[]{}|;:,.<>?";

    function generatePassword(length, includeUpper, includeNumbers, includeSpecial) {
      if (length < 1) return "";

      let charPool = LOWERCASE;
      if (includeUpper) charPool += UPPERCASE;
      if (includeNumbers) charPool += NUMBERS;
      if (includeSpecial) charPool += SPECIAL;

      if (charPool.length === 0) {
        alert("请至少选择一种字符类型!");
        return "";
      }

      let password = "";
      for (let i = 0; i < length; i++) {
        const idx = Math.floor(Math.random() * charPool.length);
        password += charPool[idx];
      }
      return password;
    }

    const lenInput = document.getElementById('len');
    const upperCheckbox = document.getElementById('upper');
    const numsCheckbox = document.getElementById('nums');
    const specialCheckbox = document.getElementById('special');
    const generateBtn = document.getElementById('generateBtn');
    const resetBtn = document.getElementById('resetBtn');
    const outputDiv = document.getElementById('passOut');

    function handleGenerate() {
      const length = parseInt(lenInput.value, 10);
      if (isNaN(length) || length < 6) {
        outputDiv.textContent = "长度至少为 6 位";
        return;
      }

      const pwd = generatePassword(
        length,
        upperCheckbox.checked,
        numsCheckbox.checked,
        specialCheckbox.checked
      );
      if (pwd) outputDiv.textContent = pwd;
    }

    function handleReset() {
      lenInput.value = 12;
      upperCheckbox.checked = true;
      numsCheckbox.checked = true;
      specialCheckbox.checked = true;
      outputDiv.textContent = "您的密码将在此显示";
    }

    generateBtn.addEventListener('click', handleGenerate);
    resetBtn.addEventListener('click', handleReset);
    document.addEventListener('keypress', e => e.key === 'Enter' && handleGenerate());
  </script>
</body>
</html>

进阶思考

  1. 强制包含各类字符
    当前逻辑可能生成不含数字的密码(即使勾选了)。可改进为:先从每类中各选一个字符,再随机填充剩余长度

  2. 排除易混淆字符
    添加选项:“排除 0, O, l, 1, I” 等,提升可读性。

  3. 一键复制到剪贴板

    navigator.clipboard.writeText(password).then(() => {
      alert("已复制到剪贴板!");
    });
  4. 密码强度指示器
    根据长度和字符类型,显示“弱 / 中 / 强”评级。

  5. 生成多个候选密码
    显示 3~5 个选项供用户选择。


重点总结

  • 密码强度 = 长度 × 字符多样性

  • 使用 Math.random() + 字符串索引 是简单有效的生成方式

  • 必须校验:长度合法性 + 至少一类字符被选中

  • 默认启用所有选项,引导用户创建强密码

  • 现代 UI 设计(毛玻璃、动效、等宽字体)显著提升体验

安全提示:此生成器适用于前端演示。生产环境应结合后端加密库或 Web Crypto API 生成更高安全级别的密码。


思考题

  1. 当前实现中,如果用户只勾选“特殊字符”,但长度设为 100,程序能否正常工作?为什么?

  2. 为什么 Math.random() 不适合用于生成高安全级别的密码(如银行系统)?应使用什么替代方案?

  3. 如何修改算法,确保生成的密码必定包含用户勾选的每一类字符(例如:同时包含大小写字母、数字和符号)?