在我的Web应用程序中,有两个页面处理用户帐户,即用户帐户创建/编辑页面和登录页面。除了我想要的以外,这些页面的效果与预期的差不多:
-
防止浏览器的用户名/密码列表(又名列表)显示在用户帐户创建/编辑页面上,
-
有条件地在登录页面上显示列表,
-
提交用户帐户创建/编辑页面后,有条件地显示浏览器的“保存用户名/密码”对话框(又名“保存”对话框),并且
-
防止在提交登录页面后显示保存对话框。
用户帐户创建/编辑页面上有一个“我的设备”复选框,可以选中/取消选中该复选框以控制我的网络应用中的某些功能,并允许浏览器在此页面上显示/隐藏其保存对话框和列表并在登录页面上。
虽然在帐户创建/修改页面上,该列表永远都不会显示,所以黑客无法轻易看到已经保存到浏览器的用户名/密码管理器中的用户名。但是,用户登录后,可以在此页面上更改自己的用户名和/或密码,然后提交更改,并且如果选中了“我的设备”复选框,则允许浏览器显示保存对话框。
登录页面还使用“我的设备”复选框设置,以分别在选中或不选中时允许查看列表或不查看列表。无论“我的设备”设置如何,该保存列表都永远不会显示在此页面上,因为这将导致服务器上的用户密码和浏览器中的用户密码不同步,并阻止所有者使用“自动” -“”成功登录到我的Web应用程序。
下面的页面不会显示该列表,也不会显示该列表,但是当输入新的/未保存的用户名/密码组合或更改的设置时,它也不总是显示保存对话框。
这是一个简化的帐户用户创建/编辑页面示例,该示例在Google Chrome,microsoft Edge和Firefox中正确隐藏了该列表,并在选中“我的设备”复选框时多次显示保存对话框。但是,在microsoft Internet Explorer中,永远不会显示保存对话框:
<!DOCTYPE html>
<html lang="en">
<!--
How to turn off form autocompletion
https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion#Preventing_autofilling_with_autocompletenew-password
The HTML autocomplete attribute
https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
-->
<head>
<meta charset="UTF-8">
<title>username-Password Test Edit html</title>
<!-- Dot-Font used to simulate the password type input element -->
<link type="text/css" rel="stylesheet"
href="https://cdn.rawgit.com/noppa/text-security/master/dist/text-security-disc.css">
<script src="https://cdn.jsdelivr.net/npm/ua-parser-js@0/dist/ua-parser.min.js"></script>
<style>
* { font-size: x-large; font-family: Arial; }
/* Show placeholder in normal text */
.password_empty { font-family: inherit; }
/* Show value as dots */
.password_not_empty { font-family: 'text-security-disc'; }
.column1 { position: absolute; left: 30px; }
.column2 { position: absolute; left: 190px; top: 0; }
textarea,input[type="email"],input[type="password"],input[type="text"] { height: 22px; width: 250px; padding-left: 2px; }
</style>
</head>
<body onload="pageLoad();">
<p id="message" style="opacity: 0;">
Please use the Submit button to save your information.
</p>
<form action="username_Password_Test.php" method="post" autocomplete="off"
onsubmit="return submitit();">
<!--
Hidden username and Password input 'honey-pot' elements for the browser to notice,so that it doesn't show the usernames/passwords list.
-->
<div id="username_password_div" style="display: none;">
<input type="text" id="user_name" name="user_name"
placeholder="username" tabIndex=-1
autocomplete="on" />
<input type="password" id="pass_word" name="pas_word"
placeholder="password" tabIndex=-1
autocomplete="new-password" />
</div>
<br />
<label class="column1">
Full Name:
<input type="text" id="fullname" name="fullname" tabIndex=1
autocomplete="off"
class="column2"
placeholder="Enter your full name"
value="Test Me" />
</label><br />
<br />
<label class="column1">
Email:
<input type="email" id="email" name="email" class="column2" tabIndex=2
autocomplete="off"
placeholder="Enter your email"
value="test.me@email.web" />
</label><br />
<br />
<label class="column1" title="Check if this is your personal device.">
Your device:
<span class="column2"
style="white-space: nowrap;">
<input type="checkbox" id="your_device" name="your_device" tabIndex=-1
autocomplete="off"
style="margin: 3px 0;"
value="yes" />
(Leave unchecked for strict account protections.)
</span>
</label><br />
<br />
<label class="column1">
username:
<input type="text" id="username" name="username" tabIndex=3
autocomplete="off"
class="column2"
placeholder="Enter a username"
value="" />
</label><br />
<br />
<label class="column1">
Password:
<input type="text" id="password" name="password" tabIndex=4
autocomplete="off"
class="column2 password_empty"
placeholder="Enter a password"
oninput="set_password_Classname();"
value="" />
</label><br />
<label class="column1" style="margin-top: 4px;">
Show password?
<input type="checkbox" id="view_hide_password" tabIndex=-1
class="column2" style="margin: 7px 0 0 0;"
onclick="set_password_Classname(); password.focus();" />
</label><br />
<br />
<button id="submitForm" class="column1" >Submit</button><br /><br />
</form>
<script>
function pageLoad() {
var labels = document.querySelectorAll( 'label' );
var inputs,input;
// Create global variables ...
window.activeElement =
window.last_activeElement = null;
window.username = document.getElementById( 'username' );
window.password = document.getElementById( 'password' );
window.view_hide_password = document.getElementById( 'view_hide_password' );
window.submit = document.getElementById( 'submit' );
//
// Track which elements get the focus in the window.activeElement - used for
// IE/Edge to tell what element has the focus when the form is submitted,// which sets the document.activeElement to the form when the form is submitted,// thus preventing the form submit submitit function to check which element
// actually has the focus.
//
document.addEventListener( 'focus',setfocus,true );
document.addEventListener( 'focusout',unsetfocus,true );
set_password_Classname();
setfocus( username );
} // End of pageLoad() function.
function setfocus( target ) {
var target_wtx_context,activeElement_wtx_context;
//
// Is the target parameter missing or it can't be focused on,then use the
// event's target as the element to be focused on ...
//
target = ( ( ( target !== undefined ) && ( target.autofocus !== undefined ) )
? target
: ( ( event !== undefined ) &&
( event.target !== undefined ) &&
( event.target.autofocus !== undefined )
? event.target
: null ) );
//
// Get the target's wtx-context,unless the target is the submit button because
// they don't have them.
//
if( ( target.nodename !== 'BUTTON' ) || ( target.id !== 'submitForm' ) ) {
target_wtx_context = getWTXContext( target );
//
// If the target has a wtx-context,then set the activeElement's
// wtx-context.
//
if( target_wtx_context ) {
activeElement_wtx_context = ( ( activeElement )
? activeElement.getattribute( 'wtx-context' )
: null );
} // End of if( target_wtx_context ) ...
} // End of if( ( target.nodename !== 'BUTTON' ) ||
// ( target.id !== 'submitForm' ) ) ...
//
// If the submit button or the current target and the activeElement aren't the
// same,then set the activeElememt to the current target ...
//
if( ( ( target.nodename === 'BUTTON' ) &&
( target.id === 'submitForm' ) ) ||
( ( target_wtx_context !== activeElement_wtx_context ) &&
( isFocusable( target ) ) ) ) {
activeElement = target;
// Focus on the current target,if it isn't the submit button ...
if( ( target.nodename !== 'BUTTON' ) ||
( target.id !== 'submitForm' ) ) {
target.focus();
}
else {
submitit();
} // End of if( ( target.nodename !== 'BUTTON' ) ||
// ( target.id !== 'submitForm' ) ) ...
// else ...
}
else if( last_activeElement ) {
// The current element and the activeElement are the same.
activeElement = last_activeElement;
}
else {
activeElement = document.active_Element;
} // End of if( ( ( target.nodename === 'BUTTON' ) &&
// ( target.id === 'submitForm' ) ) ||
// ( ( target_wtx_context !== activeElement_wtx_context ) &&
// ( isFocusable( target ) ) ) ) ...
// else if( last_activeElement ) ... else ...
} // End of setfocus( target ) function.
function getWTXContext( target ) {
//
// The wtx-context attribute that the Google Chrome browser adds to many
// elements is useful for comparing elements rather than the
// 'fields/values' in element objects,but not all browsers add the wtx-content
// attribute,so this function is used to create a unique value when the
// getattribute( 'wtx-content' ) function-call returns a null value.
//
var wtx_context = ( ( target !== null )
? target.getattribute( 'wtx-context' )
: null );
return ( wtx_context
? wtx_context
: ( ++getWTXContext.counter ).toString() + '-wtx' );
} // End of getWTXContext( target ) function.
getWTXContext.counter = 1;
function unsetfocus() {
var target = event.target;
if( isFocusable( target ) ) {
last_activeElement = target;
} // End of if( isFocusable( target ) ) ...
} // End of unsetfocus() function.
function isFocusable( target ) {
return !( ( target.nodename == 'BODY' ) ||
( target.nodename == 'DIV' ) ||
( target.nodename == 'SPAN' ) )
} // End of isFocusable( target ) function.
function set_password_Classname() {
//
// Toggle between the normal text class and the dot-font in the pseudo-
// password input "password" type text element. This allows the user to
// view/hide the password value that they type into the input field.
// Additionally,the password-empty allows the placeholder to be readable
// when the pseudo- password input field doesn't contain a value.
//
var message = document.getElementById( 'message' );
var normal_text = 'password_empty';
// Remove the password_{not_}empty class ...
if( password.classList.contains( 'password_empty' ) ) {
password.classList.remove( 'password_empty' );
}
else if( password.classList.contains( 'password_not_empty' ) ) {
password.classList.remove( 'password_not_empty' );
} // End of if( password.classList.contains( 'password_empty' ) ) ...
// else if( password.classList.contains( 'password_not_empty' ) ) ...
if( view_hide_password !== null ) {
if( !view_hide_password.checked ) {
password.classList.add( ( password.value.trim().length > 0 )
? 'password_not_empty'
: 'password_empty' );
}
else {
// Show regular text in the password field ...
password.classList.add( normal_text );
password.type = 'text';
} // End of if( !view_hide_password.checked ) ... else ...
} // End of if( ( view_hide_password !== null ) ...
} // End of set_password_Classname() function.
function submitit() {
var pass_word,user_name;
if( activeElement &&
( activeElement.nodename === 'BUTTON' ) &&
( activeElement.id === 'submitForm' ) ) {
if( document.getElementById( 'your_device' ).checked ) {
//
// Make the pseudo-password input type text element a real password field
// so that the browser will display the save-dialog when the username and
// password values haven't been saved before or have been changed.
//
password.type = 'password';
} // End of if( document.getElementById( 'your_device' ).checked ) ...
// The following errors,saying that submit() isn't a function.
// activeElement.form.submit();
// This works and submits the form ...
( Object.getPrototypeOf( activeElement.form ).submit ).
call( activeElement.form );
}
else {
// The form is being submitted,but the activeEement isn't the submit button.
//
// Display a message telling the user to use the submit button to submit the
// form.
//
if( message.timer ) clearInterval( message.timer );
message.style.opacity = 1; // Full opacity.
message.duration = 10; // Start from 10,subtract 1 every 1/8 second.
message.timer = setInterval(
function() {
var currentOp = getcomputedStyle( message ).
getPropertyValue( 'opacity' );
var duration = parseFloat( message.duration );
if( duration > 0 )
message.duration = ( duration - 1 ).toString();
else {
if( currentOp > 0 )
currentOp -= 0.1;
else {
currentOp = 0;
clearInterval( message.timer );
} // End of if( currentOp > 0 ) ...
// else ...
message.style.opacity = currentOp.toString();
} // End of if( duration = > 0 ) ...
// else ...
},125 );
} // End of if( activeElement &&
// ( activeElement.nodename === 'BUTTON' ) &&
// ( activeElement.id === 'submitForm' ) ) ...
return false;
} // End of submitit() function.
</script>
</body>
</html>
谢谢