This is may be little confused ill try best to explain. I made a php website where a user gets logout if he is inactive/idle for 5 minutes. I have done this using JavaScript, I will provide code also. Now the main problem is suppose I have two pages "one.php" , "two.php" and both the pages are using same JavaScript code to logout. Now suppose I have opened both the pages in two different tabs of the browser and let say I am working on one.php, But After 5 minutes because my two.php was inactive I will be logout even if I am working on one.php. SO help me guys how to prevent this. don't get confuses with the very first line of code, I checked 15 seconds of inactivity but in comments it says 10 minutes
var IDLE_TIMEOUT = (1/4) * 60; // 10 minutes of inactivity
var _idleSecondsCounter = 0;
document.onclick = function() {
_idleSecondsCounter = 0;
};
document.onmousemove = function() {
_idleSecondsCounter = 0;
};
document.onkeypress = function() {
_idleSecondsCounter = 0;
};
window.setInterval(CheckIdleTime, 1000);
function CheckIdleTime() {
_idleSecondsCounter++;
console.log(_idleSecondsCounter);
var oPanel = document.getElementById("SecondsUntilExpire");
if (oPanel)
oPanel.innerHTML = (IDLE_TIMEOUT - _idleSecondsCounter) + "";
if (_idleSecondsCounter >= IDLE_TIMEOUT) {
// destroy the session in logout.php
document.body.addEventListener('click', logt, true);
}
}
function logt()
{
window.open('logout.php' , '_SELF');
}
My idea: when user is active save timestamp in localstorage e.g. 'lastActivityAt': '2019-05-21T13:37:12'. And using JS setInterval run periodicaly other procedure which check key lastActivityAt every 1-5min (and logout if no activity for 5 min). Localstorage is shared between all tabs so if you make action in one tab, then other tab will detect it
You should really consider to manage your session on the server side. Meaning that requests to the server will reset a countdown there. So when a request is made after the user is logged out the server will check the expired countdown and send a proper response.
If you really want to handle this on the client side you can have a look at the localstorage which allows you to store and access data across multiple tabs/windows as long as they are for the same domain.
Related
I am using cookie-session and passport.js in Nodejs to handle user authentication:
app.use(require("cookie-session")({
secret:keys.session.secret,
resave:false,
saveUninitialized:false
}));
In my front end I have javascript that tracks keyboard and mouse events for inactivity and logs user out after 20 minutes of inactivity:
var idleTime = 0;
//Increment the idle time counter every minute.
var idleInterval = setInterval(timerIncrement, 60000); // 1 minute
//Zero the idle timer on mouse movement.
$(this).mousemove(function (e) {
idleTime = 0;
});
$(this).keypress(function (e) {
idleTime = 0;
});
function timerIncrement() {
idleTime = idleTime + 1;
if (idleTime > 19) { // 20 minutes
window.location.href = '../logout'
// window.location.href = '../login'
}
}
The issue I am having is when a user opens multiple tabs of the website and forgets about the other tabs that are open. One of the tab will log the user out. The user will not realize this until he/she tries to go to some page in the tab that they are using. Going to page would mean that they will have to go through my isLoggedIn middleware which automatically sends them to login page if they are not logged in.
The problem is that I have a massive form in my website sending nothing but post request. A use might work on it for a few minutes only to realize that nothing has been saved.
How should inactivity handeled? Should I have something checking on the backend for inactivity as well? Should it be backend only?
You can communicate between tabs using BroadcastChannel if supported, otherwise storage event from localStorage. You can find the details here, as well as a small library that can take care of all the details for you.
I recommend displaying a message warning the user that he will be logged out for inactivity in X seconds, with a button to postpone the log out.
Recently came across this problem. The scenario is, let's say I have two tabs open (A and B), I login with Tab A authenticates redirects to the home page. Then selected a link instead of just entering, I right click and pick "Open link in a new tab" thus having Tab B. At this point I start navigating for 30 mins a alert pop up saying my "Session has been finish. Please login again.". Instead of being redirected to the Login page I was redirected to the home page. (The alert must be coming for Tab A)
If I was dealing with only one Tab this isn't an Issue after the alert I would go directly to the Login Page.
I have two set of codes one handles the actual session expiration and the other gives out the alert.
This code is for the alert:
function idleLogout() {
var t;
window.onload = resetTimer;
window.onmousemove = resetTimer;
window.onmousedown = resetTimer;
window.onclick = resetTimer;
window.onscroll = resetTimer;
window.onkeypress = resetTimer;
function logout() {
alert("Session has been finish. Please login again.");
window.location.href = '{{url("")}}';
}
function resetTimer() {
clearTimeout(t);
t = setTimeout(logout, {{ env('SESSION_LIFETIME')*60*1000 }} );
}
}
idleLogout();
Code is working as intended but it can be implemented better.
Btw, if it matters using PHP Laravel 5
The problem is that you're using JavaScript to handle your timeouts. JavaScript (by default) is only confined to a single tab. While you could make use of COOKIES in JavaScript to communicate between tabs, it would make far more sense to handle session timeouts through server-side SESSION variables, which persist across tabs.
A thirty minute forced timeout can be achieved in PHP, courtesy of this answer:
if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) {
// last request was more than 30 minutes ago
session_unset(); // unset $_SESSION variable for the run-time
session_destroy(); // destroy session data in storage
}
$_SESSION['LAST_ACTIVITY'] = time(); // update last activity time stamp
Hope this helps.
I am working on specific mobile wireframe web page, where after loading of web content body for user starts timer and during this time user is about to answer question. There are two cases how the question can be answered. 1. User couldn´t answer in time and server will evaulate answer as failure. 2. User answered earlier than question time expired.
I need to prevent user to rerun script for counting seconds left. I refuse solution that after question page load frontend could communicate with database, no, communication with database is allowed for me only before and after question answering, because I want to avoid problems with lost connection during answering. Due to this, I have JS script for timing like follows:
iterator= 0;
secondsMax = 15;
elem = document.getElementById("secLeft");
elem.innerHTML = secondsMax ;
function timer() {
setTimeout(function(){
iterator++;
elem.innerHTML = secondsMax - iterator;
if(iterator == secondsMax ) {
// progress bar move... 1 question from 5
move();
iterator= 0;
//give signal to evaluate question ...
return;
}
timer();
}, 1000);
}
Resembling StackOverflow questions like this contain only answer to use ajax for not giving respond from server to reload page. But I need to programmatically prevent user to refresh on frontend to prevent cheating (but maybe ajax is good solution, but I maybe don´t understand it´s usage in this case). Do you have any idea, or solution how to do it? I am open for any criticism, well, if this solution is really bad(I am new in web technologies), please be free to advise me better one.
Thank you in advance for your time.
First of all, you must to make server-side validation to exclude cheating scenarios.
For example, any question asked has unique hash with start time linked, When you receive answer related to that hash, you can to compare time was spent...
On client-side, you can to store start time for that question in localstorage, and if page loaded finds a localstorage entry for current question hash - initialize timer with found start value.
const TIME_ALLOWED = 10e3; // 10 sec
const QUESTION_HASH = '1fc3a9903';
// start = localStorage.getItem(QUESTION_HASH) else
let start = Date.now();
let timeleft = document.getElementById('timeleft');
let timer = setInterval(() => {
let timepass = Date.now() - start;
if (timepass >= TIME_ALLOWED) {
clearInterval(timer);
timeleft.innerText = 'Time is over';
// localStorage.setItem(QUESTION_HASH, null)
return;
}
let secs = (TIME_ALLOWED-timepass) / 1000 | 0;
let mins = secs / 60 | 0;
secs = secs % 60;
if (secs < 10) secs = '0' + secs;
timeleft.innerText = `${mins}:${secs}`;
}, 500);
const answer = e => {
if (Date.now() - start >= TIME_ALLOWED) return; // disallow to answer
clearInterval(timer);
timeleft.innerText = 'Answer received';
// localStorage.setItem(QUESTION_HASH, null)
}
Time left: <span id="timeleft"></span><br/>
<button onclick="answer()">Answer</button>
Say I've a browser extension which runs JS pages the user visits.
Is there an "outLoad" event or something of the like to start counting and see how long the user has spent on a page?
I am assuming that your user opens a tab, browses some webpage, then goes to another webpage, comes back to the first tab etc. You want to calculate exact time spent by the user. Also note that a user might open a webpage and keep it running but just go away. Come back an hour later and then once again access the page. You would not want to count the time that he is away from computer as time spent on the webpage. For this, following code does a docus check every 5 minutes. Thus, your actual time might be off by 5 minutes granularity but you can adjust the interval to check focus as per your needs. Also note that a user might just stare at a video for more than 5 minutes in which case the following code will not count that. You would have to run intelligent code that checks if there is a flash running or something.
Here is what I do in the content script (using jQuery):
$(window).on('unload', window_unfocused);
$(window).on("focus", window_focused);
$(window).on("blur", window_unfocused);
setInterval(focus_check, 300 * 1000);
var start_focus_time = undefined;
var last_user_interaction = undefined;
function focus_check() {
if (start_focus_time != undefined) {
var curr_time = new Date();
//Lets just put it for 4.5 minutes
if((curr_time.getTime() - last_user_interaction.getTime()) > (270 * 1000)) {
//No interaction in this tab for last 5 minutes. Probably idle.
window_unfocused();
}
}
}
function window_focused(eo) {
last_user_interaction = new Date();
if (start_focus_time == undefined) {
start_focus_time = new Date();
}
}
function window_unfocused(eo) {
if (start_focus_time != undefined) {
var stop_focus_time = new Date();
var total_focus_time = stop_focus_time.getTime() - start_focus_time.getTime();
start_focus_time = undefined;
var message = {};
message.type = "time_spent";
message.domain = document.domain;
message.time_spent = total_focus_time;
chrome.extension.sendMessage("", message);
}
}
onbeforeunload should fit your request. It fires right before page resources are being unloaded (page closed).
<script type="text/javascript">
function send_data(){
$.ajax({
url:'something.php',
type:'POST',
data:{data to send},
success:function(data){
//get your time in response here
}
});
}
//insert this data in your data base and notice your timestamp
window.onload=function(){ send_data(); }
window.onbeforeunload=function(){ send_data(); }
</script>
Now calculate the difference in your time.you will get the time spent by user on a page.
For those interested, I've put some work into a small JavaScript library that times how long a user interacts with a web page. It has the added benefit of more accurately (not perfectly, though) tracking how long a user is actually interacting with the page. It ignore times that a user switches to different tabs, goes idle, minimizes the browser, etc.
Edit: I have updated the example to include the current API usage.
http://timemejs.com
An example of its usage:
Include in your page:
<script src="http://timemejs.com/timeme.min.js"></script>
<script type="text/javascript">
TimeMe.initialize({
currentPageName: "home-page", // page name
idleTimeoutInSeconds: 15 // time before user considered idle
});
</script>
If you want to report the times yourself to your backend:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
TimeMe.js also supports sending timing data via websockets, so you don't have to try to force a full http request into the document.onbeforeunload event.
The start_time is when the user first request the page and you get the end_time by firing an ajax notification to the server just before the user quits the page :
window.onbeforeunload = function () {
// Ajax request to record the page leaving event.
$.ajax({
url: "im_leaving.aspx", cache: false
});
};
also you have to keep the user session alive for users who stays long time on the same page (keep_alive.aspxcan be an empty page) :
var iconn = self.setInterval(
function () {
$.ajax({
url: "keep_alive.aspx", cache: false });
}
,300000
);
then, you can additionally get the time spent on the site, by checking (each time the user leaves a page) if he's navigating to an external page/domain.
Revisiting this question, I know this wouldn't be much help in a Chrome Ext env, but you could just open a websock that does nothing but ping every 1 second and then when the user quits, you know to a precision of 1 second how long they've spent on the site as the connection will die which you can escape however you want.
Try out active-timeout.js. It uses the Visibility API to check when the user has switched to another tab or has minimized the browser window.
With it, you can set up a counter that runs until a predicate function returns a falsy value:
ActiveTimeout.count(function (time) {
// `time` holds the active time passed up to this point.
return true; // runs indefinitely
});
How can I redirect to the login page when the session has completed? The code should check that the user sits idle for some time and then does any other client side event. If it finds this condition, it should check the session time out, and if session completes, redirect to login page.
Checking for inactivity on a webpage will be like an attempt to listen multitude of event. This also means that if there is user interaction the a function (event handler) is going to be called quite a lot of times. If this handler/function is going to some ajax send/receive stuffs then it could ultimately make your user interface perform poorly.
Why not make the session expiration period short and auto log out the user after? That way if the user is truly active then most probably there will a request for a page within that time frame. You could also set up a timer based event which when fired will simply send dummy request to server to refresh the session as a way of letting the server know that the user is still active but just not ready to request another page yet. This would be the case where a user is editing a long text or something like that.
I hope it helps.
Session Logout after 5 minutes
<sctipt>
var interval;
$(document).on('mousemove', function () {
clearInterval(interval);
var coutdown = 5 * 60, $timer = $('.timer'); // After 6 minutes session expired (mouse button click code)
$timer.text(coutdown);
interval = setInterval(function () {
$timer.text(--coutdown);
if (coutdown === 0) {
alert("Session expired User successfully logout.");
window.location = "UserLogin.aspx";
}
}, 1000);
}).mousemove();
var interval;
$(document).on('keydown', function () {
clearInterval(interval);
var coutdown = 7 * 60, $timer = $('.timer'); // After 6 minutes session expired (keyboard button press code)
$timer.text(coutdown);
interval = setInterval(function () {
$timer.text(--coutdown);
if (coutdown === 0) {
alert("Session expired User successfully logout.");
window.location = "UserLogin.aspx";
}
}, 1000);
}).mousemove();
<sctipt>
<div class="timer">
Time of session display on page
</div>