Javascript Chrome 自动填充/自动完成没有密码值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35049555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:13:03  来源:igfitidea点击:

Chrome Autofill/Autocomplete no value for password

javascripthtmlgoogle-chrome

提问by onetwo12

When you have saved username and password for some site Chrome will autofill that username and password, but if you try to get the value for the password input field it is empty String even though there is value there ******.

当您为某个站点保存了用户名和密码时,Chrome 会自动填充该用户名和密码,但是如果您尝试获取密码输入字段的值,即使存在 ****** 值,它也是空字符串。

If you click somewhere on the page no mater where the value of the input type="password"will be filled.

如果您单击页面上的某处,则无论在哪里input type="password"都会填充的值。

This is Fiddle user/passof the structure of the html and the console.logcommand. It cannot be seen here but it can be reproduced on every page that has login form and the username and password are autofilled on the load of the page. If you inspect the value of the field before clicking anywhere else on the site it will be empty String.

这是html 结构和命令的Fiddle用户/通行证console.log。它在这里看不到,但可以在每个有登录表单的页面上复制,并且在页面加载时自动填充用户名和密码。如果您在单击站点上的任何其他位置之前检查该字段的值,它将是空字符串。

This is not the case in Firefox or Internet Explorer it will fill the value of the inputelement with the password.

在 Firefox 或 Internet Explorer 中不是这种情况,它会input用密码填充元素的值。

I am using Windows 7 Ultimate 64-bit OS and Google Chrome version is 48.0.2564.97 m

我使用的是 Windows 7 Ultimate 64 位操作系统,Google Chrome 版本为 48.0.2564.97 m

Is this normal behavior, bug or?

这是正常行为,错误还是?

UPDATE:

更新:

If you click on F5 to reload the page and inspect the password field the value for password will be there. If you click the reload button in Chrome in top left corner the value for the password field will be empty string.

如果您单击 F5 重新加载页面并检查密码字段,密码值将在那里。如果您单击 Chrome 左上角的重新加载按钮,密码字段的值将为空字符串。

采纳答案by Adam Hamilton

This seems to be a bug in Chrome. When Chrome auto-fills a password on an initial page load (but not a refresh), the value appears in the form field on-screen, but querying passwordField.valuein Javascript returns an empty string. If you depend on seeing that value in Javascript, this prevents you from doing so. Once the user does any other action on the page, such as clicking anywhere on the page, the value suddenly becomes visible to Javascript.

这似乎是 Chrome 中的一个错误。当 Chrome 在初始页面加载(但不是刷新)时自动填充密码时,该值会出现在屏幕上的表单字段中,但passwordField.value在 Javascript 中查询会返回一个空字符串。如果您依赖于在 Javascript 中看到该值,这将阻止您这样做。一旦用户在页面上执行任何其他操作,例如单击页面上的任意位置,该值就会突然对 Javascript 可见。

I'm not actually 100% sure if this is a bug, or if there is a security reason for doing this such as preventing a hidden frame from stealing your password by tricking the browser into filling it in.

我实际上并不能 100% 确定这是否是一个错误,或者是否有这样做的安全原因,例如通过欺骗浏览器填写密码来防止隐藏框架窃取您的密码。

A workaround that we have used is to detect the background color change that Chrome makes to fields that it has auto-filled. Chrome colors the background of auto-filled fields yellow, and this change is always visible to Javascript even when the value is not. Detecting this in Javascript lets us know that the field was auto-filled with a value, even though we see the value as blank in Javascript. In our case, we have a login form where the submit button is not enabled until you fill in something in the password field, and detecting either a value or the auto-fill background-color is good enough to determine that something is in the field. We can then enable the submit button, and clicking the button (or pressing enter) instantly makes the password field value visible to Javascript because interacting with the page fixes the problem, so we can proceed normally from there.

我们使用的一种解决方法是检测 Chrome 对其自动填充的字段所做的背景颜色更改。Chrome 将自动填充字段的背景着色为黄色,即使值不存在,Javascript 也始终可以看到此更改。在 Javascript 中检测到这一点让我们知道该字段自动填充了一个值,即使我们在 Javascript 中将该值视为空白。在我们的例子中,我们有一个登录表单,其中提交按钮在您在密码字段中填写某些内容之前不会启用,并且检测值或自动填充背景颜色足以确定该字段中有某些内容. 然后我们可以启用提交按钮,单击按钮(或按 Enter 键)立即使密码字段值对 Javascript 可见,因为与页面交互可以解决问题,

回答by Andy Mercer

Working Answer as of July 8, 2016

截至 2016 年 7 月 8 日的工作答案

Adam correctly statedthis is a bug (or intended behavior). However, none of the previous answers actually say how to fix this, so here is a method to force Chrome to treat the autocompleted value as a real value.

亚当正确地指出这是一个错误(或预期的行为)。但是,之前的答案实际上都没有说明如何解决此问题,因此这里有一种方法可以强制 Chrome 将自动完成的值视为真实值。

Several things need to happen in order, and this needs to only run in Chrome and not Firefox, hence the if.

有几件事需要按顺序发生,这需要只在 Chrome 而不是 Firefox 中运行,因此if.

First we focus on the element. We then create a new TextEvent, and run initTextEvent, which adds in a custom string that we specify (I used "@@@@@") to the beginning of the value. This triggers Chrome to actually start acting like the value is real. We can then remove the custom string that we added, and then we unfocus.

首先我们关注元素。然后我们创建一个 newTextEvent和 run initTextEvent,它将我们指定的自定义字符串(我使用“@@@@@”)添加到值的开头。这会触发 Chrome 实际上开始表现得好像值是真实的。然后我们可以删除我们添加的自定义字符串,然后我们取消焦点。



Code:

代码:

input.focus();

var event = document.createEvent('TextEvent');

if ( event.initTextEvent ) {

    event.initTextEvent('textInput', true, true, window, '@@@@@');

    input.dispatchEvent(event);

    input.value = input.value.replace('@@@@@','');

}

input.blur();


Edit August 10, 2016

编辑 2016 年 8 月 10 日

This only works right now in Chrome on Windows and Android. Doesn't work on OSX. Additionally, it will stop working at all in Sept 2016, according to:

这仅适用于 Windows 和 Android 上的 Chrome。不适用于 OSX。此外,根据以下信息,它将在 2016 年 9 月完全停止工作:

https://www.chromestatus.com/features/5718803933560832

https://www.chromestatus.com/features/57188​​03933560832

Also, I've opened a Chromium ticket.

另外,我开了一张 Chromium 票。

https://bugs.chromium.org/p/chromium/issues/detail?id=636425

https://bugs.chromium.org/p/chromium/issues/detail?id=636425

As of August 12, a member of the Chrome team said on the above ticket that the behavior won't be changing because they don't consider it a bug.

截至 8 月 12 日,Chrome 团队的一名成员在上述工单上表示,行为不会改变,因为他们不认为这是一个错误。

Long-term Work-Around Suggestion:

长期解决方案建议:

That said, the current behavior has been tweaked from when it was first implemented. The user no longer has to interact with the password input for the value to be reported. The user now just needs to interact (send a mouse or keyboard event) with any part of the page. That means that while running validation on pageload still won't work, clicking on a submit button WILL cause Chrome to correctly report the password value. The work-around then, is to revalidate all inputs that might be autocompleted, if that is what you are trying to do, on submit.

也就是说,当前的行为已经从第一次实施时进行了调整。用户不再需要与要报告的值的密码输入进行交互。用户现在只需要与页面的任何部分进行交互(发送鼠标或键盘事件)。这意味着虽然在页面加载上运行验证仍然不起作用,但单击提交按钮将导致 Chrome 正确报告密码值。解决方法是在提交时重新验证所有可能会自动完成的输入(如果这是您尝试执行的操作)。



Edit December 13, 2016:

2016 年 12 月 13 日编辑:

A new Chromium ticket has been opened and is being received better. If interested in changing this behavior of Chrome's, please star this new ticket:

一张新的 Chromium 票已打开,并且收到的效果更好。如果有兴趣改变 Chrome 的这种行为,请在这张新票上加注星标:

https://bugs.chromium.org/p/chromium/issues/detail?id=669724

https://bugs.chromium.org/p/chromium/issues/detail?id=669724

回答by Ben

Continuing from what Andy Mercer said, here's my work around. Like a lot of people, I don't need the actual password value. I really just need to know that the password box has been autofilled, so that I can display the proper validation messages.

继续Andy Mercer 所说的,这是我的工作。像很多人一样,我不需要实际的密码值。我真的只需要知道密码框已自动填充,以便我可以显示正确的验证消息。

Personally, I would not use suggested solution to detect the background color change cause by Chrome's autofill. That approach seems brittle. It depends on that yellow color never changing. But that could be changed by an extension and be different in another Blink based browser (ie. Opera). Plus, there's no promise Google wont use a different color in the future. My method works regardless of style.

就个人而言,我不会使用建议的解决方案来检测 Chrome 自动填充导致的背景颜色变化。这种方法似乎很脆弱。这取决于永远不会改变的黄色。但这可以通过扩展程序进行更改,并且在另一个基于 Blink 的浏览器(即 Opera)中会有所不同。另外,不能保证 Google 将来不会使用不同的颜色。无论风格如何,我的方法都有效。

First, in CSS I set the content of the INPUTwhen the -webkit-autofilpseudo-class is applied to it:

首先,在 CSS 中,我设置了应用伪类INPUT时的内容-webkit-autofil

input:-webkit-autofill {
  content: "\feff"
}

Then, I created a routine to check for the content to be set:

然后,我创建了一个例程来检查要设置的内容:

const autofillContent = `"${String.fromCharCode(0xFEFF)}"`;
function checkAutofill(input) {
    if (!input.value) {
        const style = window.getComputedStyle(input);
        if (style.content !== autofillContent)
            return false;
    }

    //the autofill was detected
    input.classList.add('valid'); //replace this. do want you want to the input
    return true;
}

Lastly, I polled the inputto allow the autofill time to complete:

最后,我轮询input以允许自动填充时间完成:

const input = document.querySelector("input[type=password]");

if (!checkAutofill(input)) {
    let interval = 0;
    const intervalId = setInterval(() => {
        if (checkAutofill(input) || interval++ >= 20)
            clearInterval(intervalId);
    }, 100);
}

回答by SamJakob

Here's my solution to this issue:

这是我对这个问题的解决方案:

$(document).ready(function(){
  if ( $("input:-webkit-autofill").length ){
    $(".error").text("Chrome autofill detected. Please click anywhere.");
  }
});

$(document).click(function(){
  $(".error").text("");
});

Basically, clicking makes the input visible to the user, so I ask the user to click and when they do, I hide the message.

基本上,点击使输入对用户可见,所以我要求用户点击,当他们点击时,我隐藏消息。

Not the most elegant solution but probably the quickest.

不是最优雅的解决方案,但可能是最快的。

回答by crsw

Another option as of Dec. 16 / Chrome 54

12 月 16 日/Chrome 54 的另一种选择

I can't get the value of the password field, but, after "a short while", I can get the length of the password by selecting it, which is sufficient for me to enable the submit button.

我无法获取密码字段的值,但是,在“一小会儿”之后,我可以通过选择它来获取密码的长度,这足以让我启用提交按钮。

setTimeout(function() {
  // get the password field
  var pwd = document.getElementById('pwd');
  pwd.focus();
  pwd.select();
  var noChars = pwd.selectionEnd;
  // move focus to username field for first-time visitors
  document.getElementById('username').focus()
  if (noChars > 0) {
    document.getElementById('loginBtn').disabled = false;
  }
}, 100);

回答by Frozen Crayon

The workaround specified by Adam:

Adam 指定的解决方法:

... detect the background color change that Chrome makes to fields that it has auto-filled. Chrome colors the background of auto-filled fields yellow, and this change is always visible to Javascript even when the value is not. Detecting this in Javascript lets us know that the field was auto-filled with a value, even though we see the value as blank in Javascript

...检测 Chrome 对其自动填充的字段所做的背景颜色更改。Chrome 将自动填充字段的背景着色为黄色,即使值不存在,Javascript 也始终可以看到此更改。在 Javascript 中检测到这一点让我们知道该字段已自动填充了一个值,即使我们在 Javascript 中将该值视为空白

I did like this:-

我确实喜欢这样:-

getComputedStyle(element).backgroundColor === "rgb(250, 255, 189)"

where rgb(250, 255, 189) is the yellow color Chrome applies to auto filled inputs.

其中 rgb(250, 255, 189) 是 Chrome 应用于自动填充输入的黄色。

回答by bbeckford

I have found a solution to this issue that works for my purposes at least.

我找到了一个解决这个问题的方法,它至少对我的目的有用。

I have a login form that I just want to hit enter on as soon as it loads but I was running into the password blank issue in Chrome.

我有一个登录表单,我只想在它加载后立即按回车键,但我在 Chrome 中遇到了密码空白问题。

The following seems to work, allowing the initial enter key to fail and retrying again once Chrome wakes up and provides the password value.

以下似乎有效,允许初始输入键失败并在 Chrome 唤醒并提供密码值后再次重试。

$(function(){

    // bind form submit loginOnSubmit
    $('#loginForm').submit(loginOnSubmit);

    // submit form when enter pressed on username or password inputs
    $('#username,#password').keydown(function(e) {
        if (e.keyCode == 13) {
            $('#loginForm').submit(e);
            return false;
        }
    });

});

function loginOnSubmit(e, passwordRetry) {

    // on submit check if password is blank, if so run this again in 100 milliseconds
    // passwordRetry flag prevents an infinite loop
    if(password.value == "" && passwordRetry != true)
    {
        setTimeout(function(){loginOnSubmit(e,true);},100);
        return false;
    }

    // login logic here
}

回答by Ian

Just wrote an angular directive related to this. Ended up with the following code:

刚刚写了一个与此相关的角度指令。最终得到以下代码:

if ('password' == $attrs.type) {
      const _interval = $interval(() => { //interval required, chrome takes some time to autofill
          if ($element.is(':-webkit-autofill')) { //jQuery.is()
              //your code
              $interval.cancel(_interval);
          }
      }, 500, 10); //0.5s, 10 times
}

ps: it wont detect 100% of the times, chrome might take longer than 5 seconds to fill the input.

ps:它不会检测到 100% 的时间,chrome 可能需要超过 5 秒来填充输入。

回答by harry

$element.is("*:-webkit-autofill")

works for me

为我工作

回答by drewzh

With Angular, the new behaviour in Chrome (only allowing autofilled values to be read after the user has interaction with the page) manifests itself as an issue when you're using Angular's validation functionality in certain scenarios (for e.g using standard method/action attributes on the form). As the submit handler is executed immediately, it does not allow the form validators to capture the autofilled values from Chrome.

使用 Angular,Chrome 中的新行为(仅允许在用户与页面交互后读取自动填充值)在某些情况下(例如使用标准方法/操作属性)使用 Angular 的验证功能时会显示为问题在表格上)。由于提交处理程序是立即执行的,因此它不允许表单验证器从 Chrome 捕获自动填充的值。

A solution I found for this to explicitly call the form controllers $commitViewValuefunction in the submit handler to trigger a revalidation before checking form.$validor form.invalidetc.

我发现这个明确的溶液呼叫控制器的形式$commitViewValue在提交处理函数检查之前触发再验证form.$validform.invalid等。

Example:

例子:

function submit ($event) {
    // Allow model to be updated by Chrome autofill
    // @see http://stackoverflow.com/questions/35049555/chrome-autofill-autocomplete-no-value-for-password
    $scope.loginModule.$commitViewValue();

    if ($scope.loginModule.$invalid) {
        // Disallow login
        $scope.loginModule.$submitted = true;
        $event.preventDefault();
    } else {
        // Allow login
    }
}

Although this is working for us so far, I would be very interested if someone has found another, more elegant work around for the issue.

尽管到目前为止这对我们有用,但如果有人找到另一个更优雅的解决方法来解决这个问题,我会非常感兴趣。