彻底解决浏览器自动填充账号密码问题

15,920 阅读2分钟

-背景介绍

出于对安全的考虑,项目中要禁止浏览器的自动填充密码功能,经过和项目经理的一顿掰头(用户自己点的记住密码,有点过分了),最后在项目经理的一阵讨好下,本着对项目负责的精神,还是给他做了

实现思路

经过一顿搜索后大概找到了一下几个方案

  • 设置autocomplete="off"
  • 设置autocomplete="new-password",
  • 在用户名密码输入框之前, 再写假的密码框让他填充
  • 将两个input框分开,在中间加其他的输入框,设置定位或透明度将他隐藏

进过在google和edeg上测试,发现都不能满足要求,特别是之前记住过密码时,只要界面的password框聚焦就会弹出账号密码选择框,不管你怎么设置

既然问题再type="password"上,那没办法了,只能自己动手用type="text"的输入框模拟实现了,这样就不会被检测为password,也就不可能有填充了。

具体实现讲解

注意:下面的代码基于vue2+element

先上完整代码

<template>
  <div>
    {{ form.password }}
    <el-form :model="form" :rules="rules" ref="loginform">
      <el-form-item label="账号" prop="userName">
        <el-input v-model="form.userName" type="text" placeholder="请输入账号" />
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <input
        ref="passwordInput"
        type="text"
        v-model="password"
        @input="inputPassword"
        placeholder="请输入登录密码"
        class="el-input__inner"
        />
      </el-form-item>
    </el-form>
    <el-button @click="handleSubmit">登录</el-button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      password: "",
      form: {
        userName: "",
        password: "",
      },
      rules: {
        userName: [
          { required: true, message: "用户不能为空", trigger: "blur" },
        ],
        password: [
          { required: true, message: "密码不能为空", trigger: "blur" },
        ]
      },
    };
  },
  methods: {
    inputPassword(e) {
      let value = e.target.value;   // 当前的值
      let oldVal = this.form.password;  // 之前的值
      let passwordShow = "";    // 当前输入下需要显示的值,及n个*的字符串
      let text = "";    // 当前input事件输入的值,如果是删除就没有值
      // 当前input指针的位置,不一定是在最后
      let startPoint = e.target.selectionStart;
      let endPoint = e.target.selectionEnd;
      if (!value) {
        this.form.password = "";
        this.password = "";
        return;
      }
      let leftNum = 0;  // 输入后左边保留多少
      let rightNum = 0; // 输入后右边保留多少
      let isLeft = true;
      for (let i = 0; i < value.length; i++) {
        passwordShow += "*";
        if (value[i] == "*") {
          if (isLeft) {
            leftNum++;
          } else {
            rightNum++;
          }
          continue;
        }
        text += value[i];
        isLeft = false;
      }

      if (text) {
        this.form.password =
          oldVal.slice(0, leftNum) +
          text +
          oldVal.slice(oldVal.length - rightNum);
      } else {
        // if (startPoint >= value.length) {
          this.form.password =
            oldVal.slice(0, startPoint) +
            oldVal.slice(oldVal.length - leftNum - rightNum + startPoint);
        // } else {
        //   this.form.password =
        //     oldVal.slice(0, startPoint) +
        //     oldVal.slice(oldVal.length - leftNum - rightNum + endPoint);
        // }
      }
      this.password = passwordShow;
      this.$nextTick(() => {
        e.target.setSelectionRange(startPoint, startPoint);
      });
    },
    handleSubmit() {
        this.$refs.loginform.validate(valid => {
            if (valid) {
                // 登录
            }
        })
    }
  },
};
</script>

效果图

当密码框聚焦时不会有之前记住的账户密码弹窗了,登录后也不会提示你是否记住密码了

image.png

关键位置讲解

  • 输入框
<el-form-item label="密码" prop="password">
        <input
        ref="passwordInput"
        type="text"
        v-model="password"
        @input="inputPassword"
        placeholder="请输入登录密码"
        class="el-input__inner"
        />
      </el-form-item>

为了彻底不显示账号密码弹框,只能用text的输入框去输入,在input事件中再去将输入置为*

  • 输入后值的处理
  1. 输入值的拼接
  2. 删除值的处理(主要是非末尾删除)

逻辑图

image.png

if (text) {
        this.form.password =
          oldVal.slice(0, leftNum) +
          text +
          oldVal.slice(oldVal.length - rightNum);
      } else {
          this.form.password =
            oldVal.slice(0, startPoint) +
            oldVal.slice(oldVal.length - leftNum - rightNum + startPoint);
      }
  • 最后要把指针还原,默认会跳到最后
this.$nextTick(() => {
    e.target.setSelectionRange(startPoint, startPoint);
  });

待解决问题

  1. 项目就一个登录界面,就没封装成组件,可考虑封装下
  2. input的blur没触发校验,点击登录才有,不知道什么原因,可手动加个事件触发