这与我在这里提出的问题有关:How can I get browser to prompt to save password?
这就是问题所在:我的浏览器无法提示我保存正在开发的网站的密码。 (我说的是当您在 Firefox 上提交表单时有时会出现的栏,上面写着“记住 yoursite.com 的密码?是/现在不/从不”)
这非常令人沮丧,因为 Firefox(以及大多数其他现代浏览器,我希望以类似的方式工作)的这个功能似乎是一个谜。这就像浏览器做的一个魔术,它在哪里查看你的代码,或者你提交的东西,或者什么,如果它“看起来”像一个带有用户名(或电子邮件地址)字段和密码字段的登录表单,它提供保存。
除了在这种情况下,在我的用户使用我的登录表单后,它没有为我的用户提供该选项,这让我发疯了。 :-)
(我检查了我的 Firefox 设置——我没有告诉浏览器“从不”这个站点。它应该会提示。)
我的问题
Firefox 使用什么启发式方法来了解何时应该提示用户保存?这应该不难回答,因为它就在 Mozilla 源代码中(我不知道在哪里看,否则我会尝试自己挖掘它)。我也没有运气从 Mozilla 开发人员那里找到有关此的博客文章或其他类似的开发人员说明。
(我可以为 Safari 或 IE 回答这个问题;我想所有的浏览器都使用非常相似的规则,所以如果我可以让它在其中一个中工作,它会在其他浏览器中工作。)
(* 请注意,如果您对我的回答与 cookie、加密或有关我如何在本地数据库中存储密码的任何其他内容有关,那么您很可能误解了我的问题。:-)
根据我所阅读的内容,我认为 Firefox 通过 form.elements[n].type == "password"
检测密码(遍历所有表单元素),然后通过在密码字段之前的文本字段的表单元素中向后搜索来检测用户名字段(更多信息 here )。您可以在 Javascript 中尝试类似的操作,看看是否可以检测到您的密码字段。
据我所知,您的登录表单必须是 <form>
的一部分,否则 Firefox 不会检测到它。在您的密码字段上设置 id="password"
可能也不会受到伤害。
如果这仍然给您带来很多问题,我建议您在 Mozilla 项目的开发人员邮件列表之一上提问(您甚至可能会收到设计该功能的开发人员的回复)。
我遇到了同样的问题并找到了解决方案:
要让浏览器要求存储密码,用户名和密码框必须在表单中,并且必须实际提交该表单。提交按钮可能会从 onclick 处理程序返回 false(因此实际上不会发生提交)。为了使浏览器恢复之前存储的密码,输入框必须存在于主 HTML 表单中,而不是通过 javascript 动态创建。可以使用 display:none 创建表单。
需要注意的是,密码是在页面加载后立即填写的,并且在整个会话期间都存在,因此可以通过注入的 javascript 读取:这会使此类攻击变得更糟。为了避免这种情况,为了登录而转发到单独的页面是合理的,它解决了您开始阅读本主题的所有问题:)。作为部分解决方案,我在提交表单时清除字段 - 如果用户注销并想再次登录,则浏览器不会填写密码,但这对我来说并不重要。
维利亚姆
return false
或 event.preventDefault()
时,由于以下错误,这将无法在 Chrome 中运行:code.google.com/p/chromium/issues/detail?id=282488
您应该查看 Mozilla Password Manager Debugging 页面和扩展编写者的 nsILoginManager docs(仅了解 Firefox 如何处理密码管理的基本技术细节)。您可以深入了解那里的答案以及那里链接的其他页面,以找出比您可能想知道的密码管理器如何与站点和扩展程序交互的更多信息。
(特别是在密码管理器调试文档中指出,确保您没有在您的 html 中将自动完成设置为关闭,因为这将抑制保存用户名和密码的提示)
这似乎适用于 Mac 上的 Firefox、Chrome 和 Safari。未在 Windows 上测试。
<form id="bridgeForm" action="#" target="loginframe" autocomplete="on">
<input type="text" name="username" id="username" />
<input type="password" name="password" id="password"/>
</form>
<iframe id="loginframe" name="loginframe" src="anyblankpage.html"></iframe>
这需要添加到页面中。不能动态添加。可以将表单和 iframe 设置为 display:none。如果您没有设置 iframe 的 src,则在您至少提交一次表单之前不会显示提示。
然后调用表单提交():
bridgeForm.submit();
动作可能是可选的,自动完成可能是可选的。没有测试过。
注意:在某些浏览器上,表单必须在服务器(不是本地主机,也不是文件系统)上运行,然后浏览器才会响应。
所以这:
http://www.mysite.com/myPage.html
不是这个:
http://126.0.0.1/myPage.html
http://localhost/myPage.html
file://directory/myPage.html
iframe
变通方法。请参阅stackoverflow.com/a/33113374/810109
对我有用 angular、chrome、firefox:(我已经搜索和测试了几个小时 - 对于 chrome,表单操作参数 (#
) 是答案。@1.21 gigawatts,谢谢!!!您的 answer 非常宝贵.)
形式
firefox 30.0 - 不需要隐藏的 iframe 和提交按钮(如下所示),但需要“login-form-autofill-fix”指令来识别自动填充的凭证,如下所示:
<form name="loginForm" login-form-autofill-fix action="#" target="emptyPageForLogin" method="post" ng-submit="login({loginName:grpEmail,password:grpPassword})">
<input type="text" name=username" id="username" ng-model="grpEmail"/>
<input type="password" name="password" id="password" ng-model="grpPassword"/>
<button type="submit">Login</button>
</form>
隐藏的 iframe
chrome 35.0 - 不需要上述指令,但需要隐藏 iframe 和真实表单上的提交按钮。隐藏的 iframe 看起来像
<iframe src="emptyPageForLogin.html" id="emptyPageForLogin" name="emptyPageForLogin" style="display:none"></iframe>
角度指令(使用 jqLite)
这适用于角度 1.2.18
module.directive('loginFormAutofillFix', function() {
return function(scope, elem, attrs) {
if(!attrs.ngSubmit) {
return;
}
setTimeout(function() {
elem.unbind("submit").bind("submit", function(e) {
//DO NOT PREVENT! e.preventDefault();
elem.find("input").triggerHandler("input");
scope.$apply(attrs.ngSubmit);
});
}, 0);
});
修正案
经过一些测试,我意识到,chrome 需要通过角度登录方法(200 毫秒)稍微超时 - 看起来,重定向有时对于密码管理器来说太快了。
更好地清除浏览器缓存...每次更改
iframe
变通方法。请参阅stackoverflow.com/a/33113374/810109
好吧,在 our site 上,名称为“username”的表单字段类型“text”紧跟一个名称为“password”的字段并键入“password”似乎可以解决问题。
如果您使用 AJAX 登录,请查看该源代码:https://gist.github.com/968927
它包括向隐藏的 iframe 提交登录表单,以便 IE 和 Chrome 可以检测到实际登录,而无需重新加载页面。
iframe
变通方法。请参阅stackoverflow.com/a/33113374/810109
这里的启发式方法非常简单:以特定顺序检测具有特定名称的字段。哪些,我不知道,但这在 Chrome 和 IE 中对我来说很好用:
Username field: name "login", type "text";
Password field: name "password", type "password"
Submit button: element "input", type "submit".
Element "button" type "submit" did not work.
<button type="submit">
替换为 <input type="submit">
才能使 Dashlane 正常工作。不敢相信这甚至是一件事……
我还注意到,如果登录请求后登录表单仍然存在,即使它隐藏在页面上,Chrome 也不会提供记住密码。
我猜它认为登录操作失败,因此拒绝存储无效凭据。
在 Chrome 34.0 上看到。
我建议查看 Firefox source code。它实际上是非常简单的代码。
您要查看的方法是 _onFormSubmit
、_getFormFields
和 _getPasswordFields
。
您甚至可能会发现您遇到的问题实际上是 Firefox 中一个未被发现的错误;) https://bugzilla.mozilla.org/show_bug.cgi?id=1211780
除了已经说过的很多内容之外,我还意识到不能“禁用”输入字段。我们有一个多步骤登录,首先要求输入用户名,然后在下一个屏幕上输入密码。在第二个屏幕上,我们重复了电子邮件,但禁用了它,这阻止了 Chrome 等。人。从识别为用户名的有效字段。
由于我们真的想保留那个禁用的输入字段,我们最终得到了这个 hacky 解决方法:
<input type="text" name="display-username" id="display-username" value="ENTERED_USERNAME" placeholder="Username" disabled="disabled">
<input type="text" name="username" id="username" value="ENTERED_USERNAME" placeholder="Username" style="display: none;">
<input type="password" name="password" id="password" value="" autofocus="autofocus" autocomplete="on" placeholder="Password" required="required">
我不会去推荐这个,但也许它指向某人在他们自己的代码中的某些东西:
第一个元素在禁用的输入字段中显示用户名。 Disabled 不会作为表单的一部分提交,并且浏览器无法识别 disabled 。第二个元素是正确的输入字段,type = "text" 和 name/id = "username"。这正在被浏览器识别。为了防止用户编辑它,我们用 CSS (display:none) 隐藏它。
例如,如果您在输入 type=password 之前的表单中有两个 type=text,则浏览器会为您的用户名检测最近的输入 type=text。
这没关系,另一个输入有 is=username 和 name=username
为了解决这个问题,您必须将您想要保存的用户名输入准确地放在输入密码之前
祝你好运 :-)
主要关键词在这里,
<input type="password">