记录小工具:密码生成器的开发

介绍

体验密码生成器

前往体验

什么是密码?

密码是一种用来混淆的技术,它希望将正常的(可识别的)信息转变为无法识别的信息。当然,对一小部分人来说,这种无法识别的信息是可以再加工并恢复的。密码在中文里是“口令”(password)的通称。登录网站、电子邮箱和银行取款时输入的“密码”其实严格来讲应该仅被称作“口令”,因为它不是本来意义上的“加密代码”,但是也可以称为秘密的号码。

什么是强密码?

  • 独特的: 您应该为每个帐户设置单独的密码。
  • 长的: 它的长度至少为 12 个字符。
  • 复杂的: 它包括大写和小写字母、数字和符号。

什么是随机密码生成器?

密码随机生成器是一种软件或程序,可为您的各种软件和网站的帐户随机生成密码。使用此工具,您不必时常手动更改密码,并且可以获得由各种字母、数字和符号组成的字符串组成的强密码。

您可能想知道:我可以自己创建组合随机字符的密码,那为什么还要麻烦呢?因为人们不擅长随机选择密码,而倾向于使用常见的数字、字符和名称。无论你认为自己有多聪明,计算机都很容易破解人类生成的密码。这就是为什么您应该使用我们的密码生成器。

随机密码生成器安全吗?

在选择随机密码生成器时,人们最关心的是安全性。不确定密码生成器的公司是否会知道您的新密码。这些公司与许多安全站点一样使用 HTTPS 通信协议,但它可能不如银行系统安全。

因此,在选择密码管理器或密码生成器时,最好选择信誉良好且安全级别高的。

我们的密码生成器具有安全的本地加密,使黑客无法访问创建的密码。我们不会在线存储您的详细信息。

为什么我的密码应该是唯一的?

绝对有必要为您的每个在线帐户设置一个唯一的密码。

跨帐户重复使用密码会带来重大风险。一旦黑客窃取了您的一个帐户的密码,他们就会获得对所有其他帐户的访问权限。

通过简单地向现有密码添加额外的字符、符号或数字来创建新密码并不是一个好主意。建议您使用我们的强密码生成器,这将为您提供额外的保护。

为什么我的密码应该是随机的?

强密码由大小写字母、数字和特殊字符组成,即使是最熟练的黑客也无法破解。它也应该与您的个人信息无关。如果您在密码中使用电话号码、社会安全号码、邮政编码、身份证号码、门牌号码和生日,则攻击者很容易危及您的帐户。

代码

效果图

Snipaste_2024-04-19_17-25-01.png

Html结构

<div class="password w theme-bg-color">
    <div class="content">
      <div class="tool-title">
        <svg class="icon" aria-hidden="true">
          <use xlink:href="#icon-mima1"></use>
        </svg>
        <h1>密码生成器</h1>
      </div>
      <div class="tool-main">
        <el-input class="password-input" size="large" v-model="passwordVal">
          <template #suffix>
            <div class="input-icon-box">
              <svg
                class="icon refresh-icon"
                aria-hidden="true"
                @click="handleRefreshClick"
              >
                <use xlink:href="#icon-shuaxin"></use>
              </svg>
            </div>
            <div
              class="input-icon-box copy-icon-box"
              @click="copyText(passwordVal)"
            >
              复制
            </div>
          </template>
        </el-input>
        <div class="input-icon-box m-copy-icon-box" @click="copyText(passwordVal)">
          复制
        </div>
        <div class="config-item-box">
          <span
            ><svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-peizhi"></use></svg
            ><span>配置项</span></span
          >
          <div>
            <el-checkbox
              @change="updatePassword"
              size="large"
              label="数字(0-9)"
              v-model="numbers"
            />
            <el-checkbox
              @change="updatePassword"
              size="large"
              label="小写字母(a-z)"
              v-model="lowercase"
            />
            <el-checkbox
              @change="updatePassword"
              size="large"
              label="大写字母(A-Z)"
              v-model="uppercase"
            />
            <el-checkbox
              @change="updatePassword"
              size="large"
              label="特殊字符(!@#$%^&*)"
              v-model="symbols"
            />
          </div>
          <div>
            <el-checkbox
              @change="updatePassword"
              label="排除混淆字符(1lI、0oO)"
              v-model="exclude"
            />
          </div>
        </div>
        <div class="password-length-box">
          <span
            ><svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-changdu"></use></svg
            ><span>密码长度</span></span
          >
          <el-slider
            @change="updatePassword"
            v-model="passLength"
            show-input
            class="slider"
            :min="1"
            :max="50"
          />
        </div>
        <div class="history-box">
          <div class="record-box">
            <el-checkbox label="记录历史密码" v-model="isHistory" />
            <span
              >---该功能将记录您最近生成的100个密码。并且历史记录不是存储在我们云端服务器上,而是存储在您的浏览器本地存储中。</span
            >
          </div>
          <div class="look-history-box">
            <span @click="historyPassword"
              >{{ isMore ? "隐藏历史记录" : "查看历史记录" }}
              <i class="bi bi-chevron-down"></i
            ></span>
          </div>
          <div class="remove-btn" v-if="isMore" @click="removeHistory">清除历史记录</div>
          <div class="history-content" v-if="isMore">
            <div
              class="history-pw-item"
              v-for="(item, idx) in dataMap.passList"
              :key="idx"
            >
              <span @click="copyText(item)">{{ item }}</span>
            </div>
          </div>
        </div>
        <div class="about-password-box">
          <span
            ><svg class="icon" aria-hidden="true">
              <use xlink:href="#icon-guanyu-"></use></svg
            ><span>关于密码生成器</span></span
          >
          <p>
            密码是一种用来混淆的技术,它希望将正常的(可识别的)信息转变为无法识别的信息。当然,对一小部分人来说,这种无法识别的信息是可以再加工并恢复的。密码在中文里是“口令”(password)的通称。登录网站、电子邮箱和银行取款时输入的“密码”其实严格来讲应该仅被称作“口令”,因为它不是本来意义上的“加密代码”,但是也可以称为秘密的号码。
          </p>
        </div>
      </div>
    </div>
  </div>

css样式

<style lang="scss" scoped>
.password .content {
  padding: 50px 100px;
}

.tool-main {
  padding-top: 20px;
}

.tool-title {
  display: flex;
  align-items: center;
}

.tool-title h1 {
  font-size: 24px;
}

.tool-title .icon {
  width: 2.2em;
  height: 2.2em;
  margin-right: 5px;
}

.input-icon-box {
  display: flex;
  align-items: center;
  padding: 10px 5px;
}

.copy-icon-box,
.m-copy-icon-box {
  cursor: pointer;
  background-color: var(--themeTextColor);
  margin: 5px 0;
  padding: 5px 25px;
  border-radius: 2px;
  color: #fff;
  line-height: 35px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  user-select: none;

  &:hover {
    opacity: 0.8;
  }
}

.m-copy-icon-box {
  margin-top: 10px;
  display: none;
}

.icon {
  width: 2em;
  height: 2em;
  cursor: pointer;
  margin-right: 10px;
}

.config-item-box,
.password-length-box,
.about-password-box {
  margin: 20px 0;

  span {
    font-weight: 500;
    display: flex;
    align-items: center;

    .icon {
      width: 1.2em;
      height: 1.2em;
    }
  }
}

.config-item-box {
  margin-top: 20px;
}

.password-length-box span {
  margin-right: 20px;
}

.password-length-box .slider {
  width: 400px;
}

.history-box p {
  font-size: 14px;
}

.record-box {
  font-size: 12px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;

  span {
    margin-left: 20px;
  }
}

.look-history-box {
  display: flex;
  align-items: center;

  span {
    font-size: 14px;
    cursor: pointer;
    user-select: none;
    display: flex;
    align-items: center;

    .bi {
      margin-left: 3px;
    }
  }
}

.bi-chevron-down::before {
  transform: rotate(0deg);
  transition: all 0.3s;
  vertical-align: middle;
}

.bi-chevron-down.open-more::before {
  transform: rotate(180deg);
  transition: all 0.3s;
}

.remove-btn {
  margin-top: 10px;
  background-color: red;
  width: 90px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 5px;
  padding: 8px 0;
  color: #fff;
  font-size: 12px;
  cursor: pointer;
  transition: all 0.2s;

  &:hover {
    background-color: rgb(229, 41, 41);
    transition: all 0.2s;
  }
}

.history-content {
  padding: 10px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  background-color: #fff;
  border-radius: 5px;
  margin-top: 10px;

  .history-pw-item {
    padding: 8px 0;
    width: 50%;
    overflow-wrap: break-word;

    span {
      color: rgb(12, 6, 1);
      font-weight: 500;
      font-size: 14px;
      cursor: pointer;
      transition: all 0.2s;

      &:hover {
        color: var(--linkTextColor);
        transition: all 0.2s;
      }
    }
  }

  p {
    font-size: 14px;
  }
}

.about-password-box {
  margin-top: 30px;

  p {
    font-size: 14px;
    margin: 10px 0;
  }
}

:deep(.el-input__wrapper.is-focus) {
  box-shadow: none;
}

:deep(.el-slider__runway) {
  background-color: #666;
}

:deep(.el-slider__bar) {
  background-color: var(--themeTextColor);
}

:deep(.el-slider__button) {
  border-color: var(--themeTextColor);
}

:deep(.el-checkbox__label) {
  color: var(--balckTextColor) !important;
}

:deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
  background-color: var(--themeTextColor);
  border-color: var(--themeTextColor);
}

:deep(.password-input .el-input__inner) {
  font-size: 20px;
  font-weight: 600;
  color: var(--balckTextColor);
}

.rotate-animation {
  animation: rotate 0.3s linear infinite;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

@media (max-width: 860px) {
  .password .content {
    padding: 10px;
  }

  .tool-main {
    padding: 0;
  }

  .password-input .icon {
    margin-right: 0;
  }

  .copy-icon-box {
    display: none;
  }

  .m-copy-icon-box {
    display: block;
  }

  .password-length-box .slider {
    width: 100%;
  }

  .look-history-box {
    margin-top: 10px;
  }

  .history-pw-item {
    width: 100% !important;
  }
}
</style>

定义变量

const dataMap = reactive({
  passList: [],
});

let passwordVal = ref("");
let passLength = ref(12);
let numbers = ref(true);
let lowercase = ref(true);
let uppercase = ref(true);
let symbols = ref(true);
let exclude = ref(true);
let isHistory = ref(true);
let isMore = ref(false);
let maxPw = ref(100);

定义刷新密码的方法

const updatePassword = () => {
  const charSets = {
    uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
    lowercase: "abcdefghijklmnopqrstuvwxyz",
    numbers: "0123456789",
    symbols: "!@#$%^&*()_+-=[]{}|;:,.<>?",
  };

  let allChars = "";

  for (const [key, value] of Object.entries(charSets)) {
    if (key === "exclude" && exclude.value) {
      allChars = allChars.replace(/[1lI0oO]/g, "");
    } else if (key === "symbols" && symbols.value) {
      allChars += value;
    } else if (key !== "exclude" && key !== "symbols" && eval(`${key}.value`)) {
      allChars += value;
    } else {
      allChars = allChars.replace(new RegExp("[" + value + "]", "g"), "");
    }
  }

  passwordVal.value = "";

  for (let i = 0; i < passLength.value; i++) {
    const randomIndex = Math.floor(Math.random() * allChars.length);
    passwordVal.value += allChars[randomIndex];
  }

  if (isHistory.value) {
    dataMap.passList = getStore("PASS_WORD_LIST")?.length
      ? getStore("PASS_WORD_LIST")
      : [];
    if (dataMap.passList.length < maxPw.value) {
      dataMap.passList.push(passwordVal.value);
      setStore("PASS_WORD_LIST", dataMap.passList);
    }
  }
};

页面加载或刷新时

在onMounted钩子中调用updatePassword函数,并在setup中判断浏览器是否保存了历史密码记录

onMounted(() => {
  updatePassword();
});

if (getStore("PASS_WORD_LIST")?.length) {
  dataMap.passList = getStore("PASS_WORD_LIST");
}

点击刷新按钮时给按钮添加动画

const handleRefreshClick = () => {
  const iconBox = document.querySelector(".refresh-icon");
  iconBox.classList.add("rotate-animation");

  setTimeout(() => {
    iconBox.classList.remove("rotate-animation");
  }, 500);

  updatePassword();
};

点击显示/隐藏历史记录按钮方法

const historyPassword = () => {
  isMore.value = !isMore.value;
  const moreIcon = document.querySelector(".bi-chevron-down");
  moreIcon.classList.toggle("open-more");
};

点击清楚历史记录的方法

const removeHistory = () => {
  clearStore("PASS_WORD_LIST");
  dataMap.passList = getStore("PASS_WORD_LIST");
  isMore.value = false;
};

点击赋值按钮的方法

const copyText = (val) => {
  navigator.clipboard
    .writeText(val)
    .then(() => {
      ElNotification({
        title: "成功",
        message: "您生成的密码已经复制成功!",
        type: "success",
        zIndex: 99999,
      });
    })
    .catch(() => {
      ElNotification({
        title: "失败",
        message: "复制密码时出错,请重试",
        type: "warning",
        zIndex: 99999,
      });
    });
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容