這是本文件的舊版!


Wicket - Don't autocomplete(Working)

瀏覽器的貼心有時會為開發人員帶來困擾:


相信這個畫面大家並不陌生,登入facebook、mail都會跳這個dialog;在你下次登入時,瀏覽器會自動幫你輸入帳號密碼。當你做的軟體有整合LDAP、AD、SMTP、Samba任何與帳號密碼有關的功能時,使用者會想遇到這樣的狀況嗎?


假如我根本不需要使用帳號密碼,你幫我填入我不是還要自己消掉嗎? 除此之外,在Submit後所跳出的對話盒,是另一個困擾。本篇文章會分享針對這兩個問題的治療經驗。

我撰寫此篇文章時,測試的瀏覽器分別為以下版本:

  • chrome: 70.0.3538.77
  • firefox: 63.0.1
  • ie: 11.0.9600.19129

分享的方法是給大家參考,最後要使用哪種就看應用程式需求。

Don't use type="password"

要一次解決以上兩個問題,就是不要使用password。目前看到唯一跨瀏覽器的方法,可以使用這個GitHub上MIT license的project: text-security;它是透過css去模擬密碼的外表,可以直接看demo

Declare field as Readonly

這個做法是為了解決autocomplete的問題。原理就是將password field設定為readonly,而瀏覽器針對有值或者readonly的password不會自動填入,最後再透過onfocus將readonly屬性移除就可以正常使用:

<input type="password"  readonly
     onfocus="this.removeAttribute('readonly');this.select(); this.selectionStart = this.selectionEnd = this.value.length;"/>
在IE上如果僅移除readonly屬性,會造成點擊兩次才能夠輸入密碼的問題。因為我們使用Apache Wicket,使用這種方式比較容易做成可重複使用的元件。

Apply autocomplete="nope" or autocomplete="off"

這方法不推薦使用。目前我知道autocomplete=“off”可以使用於IE,但autocomplete=“nope”只能用於chrome與firefox的某些版本。

Fake blank input field

這個做法是在form的前面塞入隱藏的欄位給瀏覽器做自動完成。最早我們使用這個方法,但它有以下缺點:

  1. 如果整合的系統相當多,你會產生許多duplicate code。
  2. 在form submit之後,如果你的real-username與瀏覽器記住的username不同,所彈出記住登入資訊的帳號,會讓使用者覺得這是個bug。
  3. 在firexo 63以後的版本依然會有自動完成的現象;也是這個原因導致我們花時間研究這個問題。

<form autocomplete="off">
  <input id="username" style="display:none" type="text" name="fakeusernameremembered">
  <input id="password" style="display:none" type="password" name="fakepasswordremembered">
 
  <input id="real-username" type="text" autocomplete="nope">
  <input id="real-password" type="password" autocomplete="new-password">
</form>
(範例程式出自於link)

這個問題除了避免使用password欄位以外,目前我沒有萬全之策。以下是我針對不同瀏覽器所觀察到的情況,版本與autocomplete部分相同:

  • IE: 宣告autocomplete=“off”後就解決了。
  • Firefox: 以Ajax Request取代傳統form的submit。
  • Chrome: 即使以Ajax Request取代傳統form的submit一樣會出現。目前發現只要在http、可信任的https,且在帳號密碼欄位消失時,才會跳出來;帳號密碼欄位消失指的像是關閉Dialog的動作。

以我們的軟體而言,最大問題是在Firefox上。這邊提供個範例給大家參考,如何做form的ajax submit,首先是html部分:

<form id="form" name="form">
<input id="user" name="user" type="text" />
<input id="passwd" name="passwd" type="password" />	 
<input id="btn" type="button" value="shit"/>
</form>
javascript部分,以JQuery為範例,我使用FormData物件來將內容轉為multipart的格式送往server:
$( document ).ready(function() {
	$('#btn').click(function(){
		console.log('submit form');
		$("#form").submit();
	});
 
    $("#form").submit(function(e){
 
		var form = $(this);
		var formData = new FormData(form[0]);
		$.ajax({
			type: "POST",
			url: 'shit.php',
			processData: false,
			contentType: false,
			data: formData, 
			success: function(data)
			{
				console.log(data); // show response from the php script.
			}
	});
		e.preventDefault();
	});
 
 
});