🛡️ 防止支付密码被浏览器保存,前端也能搞!

2,445 阅读2分钟

💻 背景介绍

最近做 PC 端支付功能,输入支付密码的时候,Chrome 很“体贴”地弹了个:

"是否保存密码?"

说实话,这功能搁登录场景,确实挺方便。 但支付密码?说难听点,万一用户真保存了,自己都忘了,或者电脑不是自己的,密码直接暴露。 于是,产品一句话:

“浏览器这个弹窗,给我去掉。”

好家伙,去掉浏览器行为,这不是在为难我初级开发。

image.png

💡 方案思路

  • 项目基于 Vue3 + TypeScript + Element Plus,常规做法是用 <el-input type="password" /> 来实现密码输入。 但只要 type="password",浏览器一定会触发保存密码提示。

所以我的思路是:

✔ 把 type 改成 text,规避浏览器的默认密码保存行为

✔ 输入框里不直接展示真实密码,输入什么都用 替换

✔ 真实密码值自己内部单独存一份;

✨ 实现步骤

基础版本

<template>
  <el-input
    v-model="pwdSymbol"
    placeholder="请输入"
    type="text"
    @input="handleInput"
    @blur="handleBlur"
  />
</template>
<script setup lang="ts">
const pwdSymbol = ref("");
const pwd = ref("");
const handleInput = (value: string) => {
  const newValue = value.replace(/●/g, "")
  const lastLength = pwdSymbol.value.length;
  if (newValue) {
    pwd.value += newValue;
  } else {
    if (!lastLength) {
      pwd.value = "";
    } else {
      const arr = pwd.value.split("");
      arr.splice(-1, 1);
      pwd.value = arr.join("");
    }
  }
  let data = "";
  for (let i = 0; i < value.length; i++) {
    data += "●";
  }
  pwdSymbol.value = data;
};
const handleBlur = () => {
  console.log(pwd.value);
};
</script>
  • pwdSymbol用来展示,所以我们还需要声明一个变量,用来存储用户真正输入的值pwd
  • handleBlur主要是为了查看我们输入的密码是否正确

⚠️ 遇到的问题

  • 只能支持「从最后一位输入」
  • 中间位置输入、删除,真实密码全乱套
  • 撤回(Ctrl+Z)直接把密码还原,真实值跟展示完全对不上

🔧 进阶方案:精准控制光标 & 禁止撤回

  • 通过 ref 获取原生 input DOM,拿到光标位置,精准处理字符串
  • 撤回操作干脆禁了,省事
// 设置input的ref
const elInputRef = ref();
const handleInput = (value: string) => {
  const el = elInputRef.value?.input;
  const cursorPos = el.selectionStart;
  const newValue = value.replace(/●/g, "");
  const lastLength = pwdSymbol.value.length;
  if (newValue) {
    if (cursorPos != lastLength) {
      // 说明不是往后添加,而是在中间插入
      const arr = pwd.value.split("");
      arr.splice(cursorPos - 1, 0, newValue);
      pwd.value = arr.join("");
    } else {
      if (value.length === 1) {
        // 防止选择内容直接替换
        pwd.value = newValue;
      } else {
        pwd.value += newValue;
      }
    }
  } else {
    if (!lastLength) {
      pwd.value = "";
    } else {
      // 需要辨别是删除还是撤回
      const arr = pwd.value.split("");
      arr.splice(cursorPos, 1);
      pwd.value = arr.join("");
    }
  }
  let data = "";
  for (let i = 0; i < value.length; i++) {
    data += "●";
  }
  pwdSymbol.value = data;
};
const handleKeydown = (e: KeyboardEvent) => {
  // 判断是否按下撤回快捷键(Windows: Ctrl+Z,Mac: Meta+Z)
  if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "z") {
    e.preventDefault(); // 阻止默认撤回行为
    console.log("用户进行了撤回操作");
  }
};

最终封装

嫌麻烦可以直接封装成组件,业务场景复用更方便,这里就不贴重复代码了,思路一样。

最后

这需求可能不算技术含量特别高,但实际业务里,安全和用户体验都挺重要。

如果你们项目也有类似场景,希望这篇能省你点时间。

有更好的写法,欢迎留言交流。