Dealing with session along multiple tabs - javascript

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.

Related

Multiple tabs same session, clear the session when all tabs are gone

So I recently had acceptance criteria for a site I was building that went as such:
After a user logs in to the site in any tab if they navigate to the site in a new tab they must already be logged in
When a user logs out of any tab they must log out of all tabs immediately
A user can refresh the page and stay logged in
Once all tabs are closed the user is logged out and must log back in
I didn't have access to change the server code (so this had to be done on the client)
I found this Question/Answer which was really helpful
When looking through this I had to rule out cookies because outside of doing a request to the server tab A will no know that tab B had changed the cookie
So I took some parts of the answer from the question above and started using local-storage and added an event to check for if the 'logged-in' state was changed which allowed me to log out in one tab and immediately log out in another without using setInterval to continuously check! Yay
But then I still had the issue of once all tabs were closed if you opened a new tab and navigated to the site you were still logged in.
I tried some possible solutions like having a counter of the tabs that has a session open, decrement and increment on tab close/open (using window.onbeforeunload). ISSUE: refresh of the site when there is only one tab active would log you out. Everything I could think of had an edge case where it didnt work.
local-storage + session-storage!
I would store the value logged-in in both the local-storage and the session storage, when a window was loaded (either a new tab or a refresh of the existing one) it would check local-storage for the 'logged-in' value and if it was not there it would check session-storage!
Basically I am using session-storage to handle the refresh of a page and local-storage to handle multiple tabs. Each time a window/tab is unloaded (closed or refreshed) I delete the local-storage 'logged-in' and when I come back into the page if it is in session-storage but not in local-storage I put it back into local-storage from the session-storage and continue as an authenticated user
Here is the code for this:
On login:
localStorage.setItem('logged-in', true);
sessionStorage.setItem('logged-in', true);
In my base component:
window.onbeforeunload = (event) => {
localStorage.removeItem('logged-in');
}
let loggedIn = localStorage.getItem('logged-in');
let sessionLoggedIn = sessionStorage.getItem('logged-in');
if(!loggedIn) {
if(sessionLoggedIn) {
localStorage.setItem('logged-in', JSON.parse(sessionLoggedIn));
//go to authenticated space
window.location.href = '/authenticated';
} else {
//go to login
window.location.href = '/login';
}
} else {
//go to authenticated space
window.location.href = '/authenticated';
}
window.addEventListener('storage', (event) => {
if (event.key == 'logout' && event.newValue) {
sessionStorage.removeItem('logged-in');
localStorage.removeItem('logout');
window.location.href = '/login';
}
});
On logout
localStorage.setItem('logout', true)
Hope this helps some of you if you ever find yourself in a similar situation

OnSelectedIndexChanged and AutoPostBack

I found some javascript code on here that will display a session timeout warning and a message to inform the user that they have been logged out (as shown below) However my issue with this code is that if the user is not in front of the computer to click the ok button on either one of the alerts no further action is taken. So at the moment the timeout warning is set to be displayed 1 minute before the redirect, when that warning pops up the timer is halted until the user clicks the button and the second message pops up 1 minute after the user clicks the ok button then the redirect doesn't happen until the user clicks the button on that warning. The biggest of the issues here for me is that obviously the actual session timer is completely separate to these javascript timers so if the user is not in front of the screen when the first warning message pops up saying they have a minute before the session expires and that minute passes, then they see the message and click ok, they have not been redirected and will think they have one minute left but the session has already expired and I have code in each page the timer runs on so that they redirect to the index page if the timer has expired and all of the session variables stored are gone so they click on something and will be redirected anyway.
Is there a better way to do this? Can I use the javascript to poll the session state and find out how much time is actually remaining rather than running a completely separated timer?
<script type="text/javascript">
var iddleTimeoutWarning = null;
var iddleTimeout = null;
function pageLoad() {
if (iddleTimeoutWarning != null)
clearTimeout(iddleTimeoutWarning);
if (iddleTimeout != null)
clearTimeout(iddleTimeout);
var millisecTimeOutWarning = <%= int.Parse(System.Configuration.ConfigurationManager.AppSettings["SessionTimeoutWarning"]) * 60 * 1000 %>;
var millisecTimeOut = <%= int.Parse(System.Configuration.ConfigurationManager.AppSettings["SessionTimeout"]) * 60 * 1000 %>;
iddleTimeoutWarning = setTimeout("DisplayIddleWarning()", millisecTimeOutWarning);
iddleTimeout = setTimeout("TimeoutPage()", millisecTimeOut);
}
function DisplayIddleWarning() {
alert("Your session will expire in one minute due to inactivity.");
}
function TimeoutPage() {
alert("Your session has expired due to inactivity.");
location.replace("index.aspx");
}
</script>
Thanks.
alert blocks the UI and any further script execution.
So just use some other form of dialog, f.e. the ones that jQuery UI provides.

Session time out using Javascript or jQuery

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>

Is it possible to detect idle time even across tabs?

I have a script that sends a time-sensitive notification to users when there is a new question directed to them. However, I found that some people leave their computers open and go grab lunch, therefore missing notifications.
I'm looking to put together a script that detects if the user is idle for 5 minutes, and if so, it would show them as 'offline' and close down notifications.
I was curious if it is possible to detect inactivity even across tabs? (for example if a user switches to another tab to Facebook.com and stays active there, they would be seen as 'active' even though they are not on our webpage specifically).
Everything that happens when the user is NOT on your side is impossible to track (luckily).
So not this is not possible (think about the security).
UPDATE
Now that I think of it. It is possible, however very unlikely that you can do it. If your name would have been Google you would have come a long way, because lots of websites use Google analytics. But other than that: NO not possible for reasons mentioned.
Store their last activity in a database table when they are active. You can use mouse movement, keypresses, or some other activity to update the timestamp. Periodically poll that table with an ajax call on the page on which the user would see their online/offline status. If the last active time is > 5 minutes, show them as offline or idle.
if I am on such a thing I use either the HTML5 Visibility API or fallback to blur and focus events observing when the user left the page and then returns... leaving means unfocus the browser window or tab (but still keeping the page open)
but since you wanna react on inactivity... hmmm you could start a timeout (of course that would need a global event delegation for many events to stop it if something happens like submit, click, change, mousemove and so on)
Code is:
var inactivityTime = function () {
var t;
window.onload = resetTimer;
document.onmousemove = resetTimer;
document.onkeypress = resetTimer;
function logout() {
alert("You are now logged out.")
//location.href = 'logout.php'
}
function resetTimer() {
clearTimeout(t);
t = setTimeout(logout, 3000)
// 1000 milisec = 1 sec
}
};
I wanted to implement this functionality on my clients website. Didnt find any idleal solution for this in web.Finally I had to twig my code,think of some logic and implement this.The code goes as below--
`/*Put this code inside script tag whereever you want to execute the inactivity popup*/
var t;
//set the timeout period
var timeoutPeriod = '${inactiveIntervalMillis}';
//detect various events
callUserEvents();
`
//remove the logged Out storage after popup is closed by user
function removeLocalStorage() {
localStorage.removeItem("loggedOut");
}
//call this function whenever we detect user activity
function resetUserActivity() {
resetTimer();
}
//If the user is logged out and it clicks on other tabs,the popup will be displayed there too
function checkIfUserLoggedOut() {
if (localStorage.getItem("loggedOut")) {
loadLoginModal("/includes/gadgets/popup-content.jsp", 400, 230,
undefined);
}
}
// Call this method when any window onloads,this helps to check if multiple tabs are opened by same site
function incrementCounter() {
checkIfUserLoggedOut();
if (localStorage.getItem("counter") == "NaN") {
localStorage.setItem("counter", "0");
} else {
var counter = parseInt(localStorage.getItem("counter")) + 1;
localStorage.setItem("counter", counter);
}
resetTimer();
}
//after time interval,this method will be called
function handleIdleTimedOut() {
//get the current localStorage Object
window.sharedCounter = localStorage.getItem("counter");
//If no tabs are opened,then popup will be shown here.
if (window.localCounter == window.sharedCounter) {
loadLoginModal("/includes/gadgets/popup-content.jsp", 400, 230,undefined);
localStorage.setItem("loggedOut", "true");
}
}
function resetTimer() {
//save counterin current Window object,and after timeout period you can match it,if by chance multiple tabs were opened,the counter will be different,popup wont be shown in current window at incorrect time.
window.localCounter = localStorage.getItem("counter");
clearTimeout(t);
t = setTimeout(handleIdleTimedOut, timeoutPeriod);
}
function callUserEvents(){
window.onload=incrementCounter
window.onscroll = resetUserActivity;
window.onmousemove = resetUserActivity;
window.ondblclick = resetUserActivity;
window.oncontextmenu = resetUserActivity;
window.onclick = resetUserActivity;
window.onkeypress = resetUserActivity;
window.onpageshow = resetUserActivity;
window.onresize = resetUserActivity;
window.onfocus = incrementCounter;
window.ondrag = resetUserActivity;
window.oncopy = resetUserActivity;
window.oncut = resetUserActivity;
window.onpaste = resetUserActivity;
}
`

how to kill a application session when a browser window is closed?

i have a problem.
I am working on a chatting application. I want to kill the session if user closes the browser window without logging off. I used 'beforeunload' function but it also fires when a postback event is fired so it's not good for me.
Please help if anyone have any idea about it.
If you use polling to get the chat data, you should kill the session if you don't get a polling request from the client for a given time.
Client:
setInterval (pollData, 10000); /* poll for new data each 10 seconds */
Server:
if (clientX.LastPollTime is over 30 seconds ago) {
clientX.killSession();
}
I suggest you to use the Alexanders approach, but In most cases setting interval time wont alone solve this problem. Because the user may be idle for some time and it may exceed the timeout period.
In order to avoid this, yo need to add one more condition over this.
if the user is idle for the timeout period then Just make an AJAX request to server and update the client status as idle.
this will avoid logging off the session if the user is idel for certain time.
And you can terminate the session if the server didnt recieve any response from client in a specified time and the status is not updated to idle (during browser close or any application hangups).
yup dear, it is okey, but in second thing as you specified that that server didn't receive any response, in my code server only checks the application session and it will find it so it will work. what i want that if the user not log off then the page is killed and after that how can we call any ajax or xmlhttp request from client side to set the application session to offline.
so please guys tell me something this is the only thing is not going well. and thanx for your response.
As you said the event window.onbeforeunload fires when the users clicks on a link or refreshes the page, so it would not a good even to end a session.
However, you can place a JavaScript global variable on your pages to identify actions that should not trigger a logoff (by using an AJAX call from onbeforeonload, for example).
The script below relies on JQuery
/*
* autoLogoff.js
*
* Every valid navigation (form submit, click on links) should
* set this variable to true.
*
* If it is left to false the page will try to invalidate the
* session via an AJAX call
*/
var validNavigation = false;
/*
* Invokes the servlet /endSession to invalidate the session.
* No HTML output is returned
*/
function endSession() {
$.get("<whatever url will end your session>");
}
function wireUpEvents() {
/*
* For a list of events that triggers onbeforeunload on IE
* check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
*/
window.onbeforeunload = function() {
if (!validNavigation) {
endSession();
}
}
// Attach the event click for all links in the page
$("a").bind("click", function() {
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function() {
validNavigation = true;
});
}
// Wire up the events as soon as the DOM tree is ready
$(document).ready(function() {
wireUpEvents();
});
This script may be included in all pages
<script type="text/javascript" src="js/autoLogoff.js"></script>
Let's go through this code:
var validNavigation = false;
window.onbeforeunload = function() {
if (!validNavigation) {
endSession();
}
}
// Attach the event click for all links in the page
$("a").bind("click", function() {
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function() {
validNavigation = true;
});
A global variable is defined at page level. If this variable is not set to true then the event windows.onbeforeonload will terminate the session.
An event handler is attached to every link and form in the page to set this variable to true, thus preventing the session from being terminated if the user is just submitting a form or clicking on a link.
function endSession() {
$.get("<whatever url will end your session>");
}
The session is terminated if the user closed the browser/tab or navigated away. In this case the global variable was not set to true and the script will do an AJAX call to whichever URL you want to end the session
This solution is server-side technology agnostic. It was not exaustively tested but it seems to work fine in my tests
PS: I already posted this answer in this question. I am not sure I should answer multiple questions that are similar or post a reference?
If you have control of sessionID cookie, just set its lifetime to 0, that makes the session die on browser close. The lifetime of the session on the open window can be controled from the server side storing the time last seen in the session and checking
if(isset($_COOKIE[session_name()])) {
setcookie(session_name(), $_COOKIE[session_name()], 0, "/"); // die # browser close
}
if(isset($_SESSION['last_time'])){
if( ( time() - $_SESSION['last_time'] ) > 300 ){ // 5 minutes timeout
// here kill session;
}
}
$_SESSION['last_time'] = time();
In the client side you can use the Daniel Melo's answer. I'm using it with one small change:
function endSession() {
// $.get("<whatever url will end your session>");
// kill the session id
document.cookie = 'MYOWNSESSID=; path=/';
}
The only pending matter is that i can't wireup events to input type[buttons] yet, i have made it with raw code, but the all thing works.

Categories

Resources