Open nicolenielsen opened 9 years ago
First of all, there is nothing in the jquery-idleTimeout plugin's code that does anything directly to the user's session. The plugin can 'ping' the server regularly (configurable via sessionKeepAliveTimer
& sessionKeepAliveUrl
variables) to let the server know the user is still alive, and, hopefully, keep the server from 'killing' the user's session before the user is 'done'.
You can turn this ping off completely: set sessionKeepAliveTimer=false
. By default, the plugin pings the server every 10 minutes.
Make sure the sessionKeepAliveUrl
variable is set to a page within your site. The server must 'see' the pings, so it 'thinks' the user is still alive and active. The sessionKeepAliveUrl
default is '/'.
Note that the plugin does not ping the server while the warning dialog (countdown timer) is visible. Your server (sometimes) kills the session when the warning dialog is visible, so this indicates to me that your server session timeout setting is shorter than the interval between pings. Or maybe the plugin's pings are not 'seen' by the server for some reason?
ASP's default session timeout is 20 minutes. Typically, you'd want to set the server's session timeout to greater than your app's session timeout. For example, if you want users to be 'timed out' after 30 minutes of inactivity, set the server's session timeout to 35 minutes. A basic ASP session tutorial is here: http://www.w3schools.com/asp/asp_ref_session.asp
Sometimes the session can be lost even though the user is active (pings, new pages, etc). This page gives some other possibilities for timeouts: http://machinesaredigging.com/2013/10/29/how-does-a-web-session-work/
Make sure you use the correct variable names to configure the plugin: spelling and case matters. It's idleTimeLimit
, not 'idleTimeActivity', though I think that's just a typo above, right? https://github.com/JillElaine/jquery-idleTimeout/wiki/Public-Configuration-Variables
Post back what you learn so that others may benefit! Thank you!
Also, please read this: http://stackoverflow.com/questions/648992/session-timeout-in-asp-net
Hi,
Thank you for your reply. I have set the sessionKeepAliveTimer = 600 but did not specify a sessionKeepAliveUrl. I believe this will get the current url instead right? I have also checked in firebug that the url is successfully being 'ping-ed'. Also my session timeout (set in web.config and IIS) is already set to 30 minutes, so it's larger than the interval between the pings. And you're right, the idleTimeActivity is only a typo. I'm using the correct name.
I tried setting the idleTimeLimit to a value less than 30 minutes, however, I still get timed out if clicking on Stay Logged In with only a few seconds left (<=5). I'm using MVC and OWIN authentication, the cookie being created by OWIN is also set to 30 minutes timespan expiration. Is there any chance someone have encountered this issue?
Many thanks!
You should load the jquery-idleTimeout-for-testing.js and watch the console in Firebug. What happens when you click the Stay Logged In button? Are you redirected to the logout page anyway?
Again, there is nothing in the jquery-idleTimeout code that actually causes a user timeout: all it does is track idleness.
It is up to the implementer (you) to cause your idle users to timeout. Typically this is done with code that executes when the user is redirected to the logout page...or with code added to the optional customCallback
variable. How have you implemented this timeout for your idle users? How do you log out your idle users? Are you using the customCallback
?
No one else has reported this problem, so I am puzzled. I am not familiar with ASP,sorry. Is the OWIN cookie set to expire after 30 minutes even if the user is not idle? What happens if you set all your server side timeouts to 35 minutes?
Okay, I can confirm that there is a bug. The plugin does 'time out' just a few seconds before the 'countdown' completes. In other words, Time Remaining may display 2-3 seconds left when timeout occurs. I will patch this as soon as possible. Thank you for your patience.
Hello,
I was wondering whether any progress has been made on this issue? I am running into the same problem.
Thanks!
I have not had time to work on code recently, but I think the code below will fix the problem. Would you please try it, and let me know?
The problem occurred because there is typically a several second delay between the starting of the dialog timer and the display of the warning dialog. The only change in the code below is to test that the warning dialog 'Time Remaining' display has reached zero before logging out the user. The result will be that the user will be given a few seconds 'grace' before being logged out.
/**
* This work is licensed under the Creative Commons Attribution-Share Alike 3.0
* United States License. To view a copy of this license,
* visit http://creativecommons.org/licenses/by-sa/3.0/us/ or send a letter
* to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
*
* Modified by: Jill Elaine
* Email: jillelaine01@gmail.com
*
* Configurable idle (no activity) timer and logout redirect for jQuery.
* Works across multiple windows and tabs from the same domain.
*
* Dependencies: JQuery v1.7+, JQuery UI, store.js from https://github.com/marcuswestin/store.js - v1.3.4+
*
* version 1.0.10
**/
/*global jQuery: false, document: false, store: false, clearInterval: false, setInterval: false, setTimeout: false, clearTimeout: false, window: false, alert: false*/
/*jslint indent: 2, sloppy: true, plusplus: true*/
(function ($) {
$.fn.idleTimeout = function (userRuntimeConfig) {
//##############################
//## Public Configuration Variables
//##############################
var defaultConfig = {
redirectUrl: '/logout', // redirect to this url on logout. Set to "redirectUrl: false" to disable redirect
// idle settings
idleTimeLimit: 1200, // 'No activity' time limit in seconds. 1200 = 20 Minutes
idleCheckHeartbeat: 2, // Frequency to check for idle timeouts in seconds
// optional custom callback to perform before logout
customCallback: false, // set to false for no customCallback
// customCallback: function () { // define optional custom js function
// perform custom action before logout
// },
// configure which activity events to detect
// http://www.quirksmode.org/dom/events/
// https://developer.mozilla.org/en-US/docs/Web/Reference/Events
activityEvents: 'click keypress scroll wheel mousewheel mousemove', // separate each event with a space
// warning dialog box configuration
enableDialog: true, // set to false for logout without warning dialog
dialogDisplayLimit: 180, // Time to display the warning dialog before logout (and optional callback) in seconds. 180 = 3 Minutes
dialogTitle: 'Session Expiration Warning', // also displays on browser title bar
dialogText: 'Because you have been inactive, your session is about to expire.',
dialogTimeRemaining: 'Time remaining',
dialogStayLoggedInButton: 'Stay Logged In',
dialogLogOutNowButton: 'Log Out Now',
// error message if https://github.com/marcuswestin/store.js not enabled
errorAlertMessage: 'Please disable "Private Mode", or upgrade to a modern browser. Or perhaps a dependent file missing. Please see: https://github.com/marcuswestin/store.js',
// server-side session keep-alive timer
sessionKeepAliveTimer: 600, // ping the server at this interval in seconds. 600 = 10 Minutes. Set to false to disable pings
sessionKeepAliveUrl: window.location.href // set URL to ping - does not apply if sessionKeepAliveTimer: false
},
//##############################
//## Private Variables
//##############################
currentConfig = $.extend(defaultConfig, userRuntimeConfig), // merge default and user runtime configuration
origTitle = document.title, // save original browser title
activityDetector,
startKeepSessionAlive, stopKeepSessionAlive, keepSession, keepAlivePing, // session keep alive
idleTimer, remainingTimer, checkIdleTimeout, checkIdleTimeoutLoop, startIdleTimer, stopIdleTimer, // idle timer
openWarningDialog, dialogTimer, checkDialogTimeout, startDialogTimer, stopDialogTimer, isDialogOpen, destroyWarningDialog, countdownDisplay, dialogDisplaySeconds, // warning dialog
logoutUser;
//##############################
//## Public Functions
//##############################
// trigger a manual user logout
// use this code snippet on your site's Logout button: $.fn.idleTimeout().logout();
this.logout = function () {
store.set('idleTimerLoggedOut', true);
};
//##############################
//## Private Functions
//##############################
//----------- KEEP SESSION ALIVE FUNCTIONS --------------//
startKeepSessionAlive = function () {
keepSession = function () {
$.get(currentConfig.sessionKeepAliveUrl);
startKeepSessionAlive();
};
keepAlivePing = setTimeout(keepSession, (currentConfig.sessionKeepAliveTimer * 1000));
};
stopKeepSessionAlive = function () {
clearTimeout(keepAlivePing);
};
//----------- ACTIVITY DETECTION FUNCTION --------------//
activityDetector = function () {
$('body').on(currentConfig.activityEvents, function () {
if (!currentConfig.enableDialog || (currentConfig.enableDialog && isDialogOpen() !== true)) {
startIdleTimer();
}
});
};
//----------- IDLE TIMER FUNCTIONS --------------//
checkIdleTimeout = function () {
var timeIdleTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000));
if ($.now() > timeIdleTimeout) {
if (!currentConfig.enableDialog) { // warning dialog is disabled
logoutUser(); // immediately log out user when user is idle for idleTimeLimit
} else if (currentConfig.enableDialog && isDialogOpen() !== true) {
openWarningDialog();
startDialogTimer(); // start timing the warning dialog
}
} else if (store.get('idleTimerLoggedOut') === true) { //a 'manual' user logout?
logoutUser();
} else {
if (currentConfig.enableDialog && isDialogOpen() === true) {
destroyWarningDialog();
stopDialogTimer();
}
}
};
startIdleTimer = function () {
stopIdleTimer();
store.set('idleTimerLastActivity', $.now());
checkIdleTimeoutLoop();
};
checkIdleTimeoutLoop = function () {
checkIdleTimeout();
idleTimer = setTimeout(checkIdleTimeoutLoop, (currentConfig.idleCheckHeartbeat * 1000));
};
stopIdleTimer = function () {
clearTimeout(idleTimer);
};
//----------- WARNING DIALOG FUNCTIONS --------------//
openWarningDialog = function () {
var dialogContent = "<div id='idletimer_warning_dialog'><p>" + currentConfig.dialogText + "</p><p style='display:inline'>" + currentConfig.dialogTimeRemaining + ": <div style='display:inline' id='countdownDisplay'></div></p></div>";
$(dialogContent).dialog({
buttons: [{
text: currentConfig.dialogStayLoggedInButton,
click: function () {
destroyWarningDialog();
stopDialogTimer();
startIdleTimer();
}
},
{
text: currentConfig.dialogLogOutNowButton,
click: function () {
logoutUser();
}
}
],
closeOnEscape: false,
modal: true,
title: currentConfig.dialogTitle,
open: function () {
$(this).closest('.ui-dialog').find('.ui-dialog-titlebar-close').hide();
}
});
countdownDisplay();
document.title = currentConfig.dialogTitle;
if (currentConfig.sessionKeepAliveTimer) {
stopKeepSessionAlive();
}
};
checkDialogTimeout = function () {
var timeDialogTimeout = (store.get('idleTimerLastActivity') + (currentConfig.idleTimeLimit * 1000) + (currentConfig.dialogDisplayLimit * 1000));
if ((($.now() > timeDialogTimeout) && (dialogDisplaySeconds <= 0)) || (store.get('idleTimerLoggedOut') === true)) {
logoutUser();
}
};
startDialogTimer = function () {
dialogTimer = setInterval(checkDialogTimeout, (currentConfig.idleCheckHeartbeat * 1000));
};
stopDialogTimer = function () {
clearInterval(dialogTimer);
clearInterval(remainingTimer);
};
isDialogOpen = function () {
var dialogOpen = $("#idletimer_warning_dialog").is(":visible");
if (dialogOpen === true) {
return true;
}
return false;
};
destroyWarningDialog = function () {
$("#idletimer_warning_dialog").dialog('destroy').remove();
document.title = origTitle;
if (currentConfig.sessionKeepAliveTimer) {
startKeepSessionAlive();
}
};
countdownDisplay = function () {
dialogDisplaySeconds = currentConfig.dialogDisplayLimit, mins, secs;
remainingTimer = setInterval(function () {
mins = Math.floor(dialogDisplaySeconds / 60); // minutes
if (mins < 10) { mins = '0' + mins; }
secs = dialogDisplaySeconds - (mins * 60); // seconds
if (secs < 10) { secs = '0' + secs; }
$('#countdownDisplay').html(mins + ':' + secs);
dialogDisplaySeconds -= 1;
}, 1000);
};
//----------- LOGOUT USER FUNCTION --------------//
logoutUser = function () {
store.set('idleTimerLoggedOut', true);
if (currentConfig.sessionKeepAliveTimer) {
stopKeepSessionAlive();
}
if (currentConfig.customCallback) {
currentConfig.customCallback();
}
if (currentConfig.redirectUrl) {
window.location.href = currentConfig.redirectUrl;
}
};
//###############################
// Build & Return the instance of the item as a plugin
// This is your construct.
//###############################
return this.each(function () {
if (store.enabled) {
store.set('idleTimerLastActivity', $.now());
store.set('idleTimerLoggedOut', false);
activityDetector();
if (currentConfig.sessionKeepAliveTimer) {
startKeepSessionAlive();
}
startIdleTimer();
} else {
alert(currentConfig.errorAlertMessage);
}
});
};
}(jQuery));
Thanks @JillElaine! The fix you posted above mostly worked. I made two slight modifications and submitted a pull request (#31). The changes:
countdownDisplay = function () {
dialogDisplaySeconds = currentConfig.dialogDisplayLimit, mins, secs;
changed to
countdownDisplay = function () {
dialogDisplaySeconds = currentConfig.dialogDisplayLimit;
var mins, secs;
as an error was thrown otherwise (claiming 'mins' wasn't defined). I also changed
countdownDisplay = function () {
...
dialogDisplaySeconds -= 1;
}, 1000);
};
to
countdownDisplay = function () {
...
if (dialogDisplaySeconds) { dialogDisplaySeconds -= 1; }
}, 1000);
};
in order to avoid displaying 'NaN' in the dialog after the counter had reached 0.
Thank you for this suggested change for the countdownDisplay to avoid NaN. I don't have time to work on my code now, but hope to improve it in the future.
Hi,
First of all, great plugin. However, I'm encountering intermittent issues such that my session timeout is set to 30 minutes, I set the idleTimeActivity to 27 minutes and the countdown timer to 3 minutes. When the timer shows up in 27 minutes in, I wait for the countdown timer to count until less than 5 seconds, and clicks on Stay Logged In button. Sometimes, the session is gone but sometimes it remains.
Any idea why this happens? Is it because ASP.NET's session expires sooner?
Thank you. Any help would be greatly appreciated!