使用JavaScript创建一个自动注销功能
在为我们的应用程序实现安全时,我们将在某一时刻检查用户在标签中的活跃度。根据用户的活跃度自动注销,总是一个好的做法。
如果应用程序处理用户的敏感或私人数据,这一点尤其重要。例如,银行账户信息。我们将看到如何根据输入事件(如按键、滚动等)使用JavaScript来做到这一点。
先决条件
要跟上本教程,你应该具备。
- 有JavaScript的基本知识。
- 具有HTML和CSS的基本知识。
- 有PHP的基本知识(可选)。
你可以使用任何技术/语言来编写后端登录脚本。
简要概述
我们将在一个基于PHP作为后台的简单登录界面的帮助下,使用JavaScript研究一个自动注销功能的实现。显示页面将有一个计数器,计算用户因不活动而被注销前的剩余秒数。
如果检测到任何事件,自动注销的计时器将被重置。
开始使用
我们将首先用HTML和CSS为登录和显示屏幕创建用户界面文件。
我不会解释用户界面片段,因为这已经超出了本文的范围,而且也不是本文的主要目的。你可以创建任何你自己的,它并不严格限于我使用的那些。
登录页面代码如下。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="assets/images/logo-sacco.png" type="image/x-icon">
<title>Sign Page | T-Bank</title>
<!-- Bootstrap CSS CDN -->
<body style="background-color: rgba(46, 51, 52, 1)">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
<!-- Font Awesome JS -->
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/solid.js"
integrity="sha384-tzzSw1/Vo+0N5UhStP3bvwWPq+uvzCMfrN1fEFe+xBmv1C/AtVX5K0uZtmcHitFZ"
crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/fontawesome.js"
integrity="sha384-6OIrr52G08NpOFSZdxxz1xdNSndlD4vdcf/q2myIUVO0VsqaGHJsB0RaBE01VTOY"
crossorigin="anonymous"></script>
<link rel="stylesheet" type="text/css" href="/sacco/style/home.css">
</head>
<div>
<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #008081">
<div class="container-fluid">
<p>
<button style="z-index: 2" type="button" id="sidebarCollapse" class="btn btn-info">
<i class="fa fa-home "></i>
<span><a href="https://sacco.terrence-aluda.com/">Home Page</a></span>
</button>
<div class="d-flex justify-content-center" style="padding: 2%; text-align: center; background-color: #008081">
<h1 style="color: white">T-BANK</h1>
</div>
</p>
</div>
</nav>
<div class="d-flex align-items-center justify-content-center vw-60 vh-70" style="padding-bottom: 3vh">
<div class="card border-dark container">
<div class="card-body border-dark row" style="background-color: #035050">
<div id="sych" class=" col-md-6 d-flex align-items-center justify-content-center">
<div class="card-body" style=" min-width: 30vw;">
<div style="text-align: center; padding-bottom: 15vh" class="card-text text-white">
<h3>Log in</h3>
</div>
<form action="https://sacco.terrence-aluda.com/sacco/backend/eng-ed-auth.php" method="post">
<div class="mb-3">
<div class="d-flex align-items-center justify-content-center vw-30">
<input class="form-control text-center" name="PhoneNo" type="text" autofocus="true" placeholder="Phone number"
id="signNum">
</div>
</div>
<div class="mb-3">
<div class="d-flex align-items-center justify-content-center vw-50">
<input type='password' name="password" class="form-control text-center" placeholder="Confirm password" id="logPass">
</div>
</div>
<div class="mb-3">
<div class="d-flex align-items-center justify-content-center vw-50">
<span id="banner" class="text-danger"></span>
</div>
</div>
<div class="mb-3" style="text-align: center">
<button id="logBtn" class="btn" style="background-color: red; color: white; "><i
class="fa fa-unlock-alt"></i> Log in</button>
</div>
</form>
</div>
</div>
<div style="background-image: url(assets/images/logo-big.jpeg); background-size: cover;" class="col-md-6">
<div style="padding-top: 60vh"
class="d-flex align-content-center align-items-center justify-content-center vw-100 vh-100">
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
这是登录页面,用户在这里输入凭证以登录到系统。样式表是托管的,所以如果你的浏览器由于CORS策略而不能正常渲染UI,你可以点击上面提供的链接查看。
样式表使用了Bootstrap 5。
登录凭证是电话号码 -
1234567890和密码 -1111。
输出

显示页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="icon" href="assets/images/logo-sacco.png" type="image/x-icon">
<title>Sign Page | T-Bank</title>
<!-- Bootstrap CSS CDN -->
<body onload="startCountdown()" style="background-color: rgba(46, 51, 52, 1)">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
<!-- Font Awesome JS -->
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/solid.js"
integrity="sha384-tzzSw1/Vo+0N5UhStP3bvwWPq+uvzCMfrN1fEFe+xBmv1C/AtVX5K0uZtmcHitFZ"
crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/fontawesome.js"
integrity="sha384-6OIrr52G08NpOFSZdxxz1xdNSndlD4vdcf/q2myIUVO0VsqaGHJsB0RaBE01VTOY"
crossorigin="anonymous"></script>
<link rel="stylesheet" type="text/css" href="/sacco/style/home.css">
</head>
<div>
<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #008081">
<div class="container-fluid">
<p>
<button style="z-index: 2" type="button" id="sidebarCollapse" class="btn btn-info">
<i class="fa fa-home "></i>
<span><a href="https://sacco.terrence-aluda.com/">Home Page</a></span>
</button>
<div class="d-flex justify-content-center" style="padding: 2%; text-align: center; background-color: #008081">
<h1 style="color: white">T-BANK</h1>
</div>
</p>
</div>
</nav>
<div class="d-flex align-items-center justify-content-center vw-60 vh-70" style="padding-bottom: 3vh">
<div class="card border-dark container">
<div class="card-body border-dark row" style="background-color: #035050">
<p class="card-text">
<h6 class="text-white">The page will take you to the login page after</h6> <h5 style="color: #0af53a" id="numCount"><h5> <h6 class="text-white">seconds of inactivity.</h6>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="https://sacco.terrence-aluda.com/sacco/js/autologout.js"></script>
</html>
这是一个显示页面,用户将在这里看到在一段时间不活动后被注销的倒计时。
注意,在body的
onload属性中启动了一个方法。我们将在JavaScript代码中讨论这个问题。
输出

PHP登录脚本
<?php
require_once "connection.php";
if($_SERVER["REQUEST_METHOD"] == "POST"){
$password = trim($_POST["password"]);
$phone = trim($_POST["PhoneNo"]);
$sql = "SELECT * FROM customers WHERE PhoneNo = '$phone' AND password = '$password'";
$stmt = $mysqli->query($sql);
if($stmt->num_rows>0){
header("Location: https://sacco.terrence-aluda.com/sacco/display.html");
}
}
$mysqli->close();
?>
这是后端脚本。同样,你可以用你喜欢的任何语言编写。它使用一个POST 方法来接收参数,删除任何尾部的空格,然后运行一个简单的SELECT 查询来检查证书是否存在。
如果凭证没有问题,我们就把用户重定向到显示页面。
三个文件的工作
这三个文件是相连的,用户首先访问登录页面并登录。在PHP脚本验证了用户的身份后,他们被允许访问显示页面。
在设定的非活动时间后,显示页面会重定向到登录页面。
Login -> [Backend aunthentication] -> Display -> (If user is inactive) -> Login
脚本
这就是自动退出功能的 "制造 "过程。
let warningTimeout = 5000;
let warningTimerID;
let counterDisplay = document.getElementById("numCount");
let logoutUrl = "https://sacco.terrence-aluda.com/sacco/eng-edtest.html";
我们首先初始化这些变量。
warningTimeout- 用于存储超时时间。warningTimerID- 用于存储定时器ID。counterDisplay- 用于存储将显示计数器数字的元素。logoutUrl- 用于存储注销后脚本将重定向到的URL地址。
function startTimer() {
// window.setTimeout returns an ID that can be used to start and stop the timer
warningTimerID = window.setTimeout(idleLogout, warningTimeout);
animate(counterDisplay, 5, 0, warningTimeout);
}
这是启动定时器的方法。
window.setTimeout() 返回一个ID,将用于启动和停止计时器。在达到超时后,调用 方法,将用户注销。idleLogout()
使用animate() 方法使计数器成为动画。我们将在接下来的部分中详细讨论这些方法。
计时器被设置为5秒,以节省我们在测试系统时的时间,但你可以适当地改变数值,例如3分钟、200秒等。
由于定时器的持续时间,我们也将动画计数器设置为运行5秒。你要把它设置成与你使用的定时器数值相匹配,如100秒为100,30秒为30,等等。
另一点需要注意的是,由于一些用户体验(UX)问题,建议设置两个计时器,一个用于等待不活动的会话,另一个用于警告用户。
这样,你可以在显示一个带有计数器的模式后,将警告计时器设置为关闭,而不是让计数器在程序的整个时间内运行。例如,10分钟用于等待不活动状态,然后30秒用于显示带有计数器的弹出窗口。
function resetTimer() {
window.clearTimeout(warningTimerID);
startTimer();
}
[];
这个建议很直接。它清除了符合超时ID的超时。它在检测到任何事件后被触发。
function idleLogout() {
window.location = logoutUrl;
}
这个函数只是在一段时间的非活动后重定向到登录页面。
function animate(obj, initVal, lastVal, duration) {
let startTime = null;
//get the current timestamp and assign it to the currentTime variable
let currentTime = Date.now();
//pass the current timestamp to the step function
const step = (currentTime) => {
//if the start time is null, assign the current time to startTime
//pass the current timestamp to the step function
const step = (currentTime) => {
//if the start time is null, assign the current time to startTime
if (!startTime) {
startTime = currentTime;
}
//calculate the value to be used in calculating the number to be displayed
const progress = Math.min((currentTime - startTime) / duration, 1);
//calculate what is to be displayed using the value gotten above
displayValue = Math.floor(progress * (lastVal - initVal) + initVal);
obj.innerHTML = displayValue;
//checking to make sure the counter does not exceed the last value(lastVal)
if (progress < 1) {
window.requestAnimationFrame(step);
} else {
window.cancelAnimationFrame(window.requestAnimationFrame(step));
}
};
//start animating
window.requestAnimationFrame(step);
}
简而言之,它获取当前的时间戳和页面加载的时间戳。然后,它利用这两个时间戳之间的差异来计算要显示的内容,并将其显示在元素中。
在我们的例子中,它显示在显示页面的一个h5 元素中。
<h5 style="color: #0af53a" id="numCount"><h5></h5></h5>
function startCountdown() {
document.addEventListener("mousemove", resetTimer);
document.addEventListener("mousedown", resetTimer);
document.addEventListener("keypress", resetTimer);
document.addEventListener("touchmove", resetTimer);
document.addEventListener("onscroll", resetTimer);
document.addEventListener("wheel", resetTimer);
startTimer();
}
最后,我们有startCountdown() 方法。这是在显示页面上的body的onload 属性中加载时触发的。
当检测到AddEventListener() 方法中包含的事件(mousemove, mousedown, keypress, touchmove, onscroll, wheel)时,resetTimer() 方法被调用以重置计时器,从而使用户保持登录状态。
下面是完整的JavaScript代码。
let warningTimeout = 5000;
let warningTimerID;
let counterDisplay = document.getElementById('numCount');
logoutUrl = "https://sacco.terrence-aluda.com/sacco/eng-edtest.html";
function startTimer() {
// window.setTimeout returns an ID that can be used to start and stop the timer
warningTimerID = window.setTimeout(idleLogout, warningTimeout);
animate(counterDisplay, 5, 0, warningTimeout);
}
//function for resetting the timer
function resetTimer() {
window.clearTimeout(warningTimerID);
startTimer();
}
// Logout the user.
function idleLogout() {
window.location = logoutUrl;
}
function startCountdown() {}
document.addEventListener("mousemove", resetTimer);
document.addEventListener("mousedown", resetTimer);
document.addEventListener("keypress", resetTimer);
document.addEventListener("touchmove", resetTimer);
document.addEventListener("onscroll", resetTimer);
document.addEventListener("wheel", resetTimer);
startTimer();
}
//the animating function
function animate(obj, initVal, lastVal, duration) {
let startTime = null;
//get the current timestamp and assign it to the currentTime variable
let currentTime = Date.now();
//pass the current timestamp to the step function
const step = (currentTime ) => {
//if the start time is null, assign the current time to startTime
if (!startTime) {
startTime = currentTime ;
}
//calculate the value to be used in calculating the number to be displayed
const progress = Math.min((currentTime - startTime) / duration, 1);
//calculate what is to be displayed using the value gotten above
displayValue = Math.floor(progress * (lastVal - initVal) + initVal);
obj.innerHTML = displayValue;
//checking to make sure the counter does not exceed the last value(lastVal)
if (progress < 1) {
window.requestAnimationFrame(step);
}else{
window.cancelAnimationFrame(window.requestAnimationFrame(step));
}
};
//start animating
window.requestAnimationFrame(step);
}
关键研究领域
该代码没有跟踪不同标签中的页面。例如,如果你在不同的标签页中登录了同一个页面,事件只重置了活动标签页中的时间。这意味着其他标签页仍然会将用户注销。我们的目标是重置所有标签页的计时器。
结论
我们研究了在纯JavaScript中创建一个自动注销功能。我们还详细研究了文件和JavaScript代码的工作情况。
用户的私人数据是非常关键的。让别人看不到另一个人的私人信息总是很重要的。自动注销功能是一个很好的解决方案。