I consider two scenarios:
User clicks on "log out" hyperlink, which call "logout.php" (that is easy)
User closes tab (window) or closes browser.
And here I do not know, what should I do.
There is a event: window.onunload which can be used perhaps like this (not tested):
<script>
var logout_php = function () {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "logout.php", true);
xhttp.send();
}
window.onunload = logout_php ;
</script>
But when the user opens more tabs and closes just one of them, he will be logged out. Probably it will log out even, when somebody refreshes the same page.
I considered to count all opened tabs with the same domain address, and if there is only one left, then will be the final logout. But this is not possible, because you can not access another windows (tabs) opened in browser.
I am sure, it must be a common problem, but I can not find appropriate answer.
thanx
Sessions are used to handle these kind of things. If you logout then your session is destroyed and if someone closes the window directly then in that case their session is destroyed as well. So, as long as you are using sessions, there is nothing to worry about.
You can try a keep_live ajax function that calls your server every 1 minute or so updating the last_checkin variable in database or so. If the tab is closed, said function is no longer being called.
In the beginning of every request check if last_checkin is within the last minute (+ some time for connection). If not, redirect to log out (and destroy session if it exists).
This is similar to session timeout. You can have this done every 5 seconds or so. If someone closes his tab and then (for some weird reason) someone else sits on the PC and opens previously closed tabs. Most likely the x time has passed since last check in and user is now logged out.
The down side is the traffic between user and server but it's not a big deal. This is how you check for chat updates anyway so it is done in many services.
Related
My question is kind of a follow-up to this somewhat old post, which is why I though of asking here, instead of just asking via comment there.
My question is straightforward: I have an online platform with very tight session restrictions (samesite, httponly, short lifetimes, etc.), and while a user is logged into the platform, they may execute payments. These payments may redirect them to an intermediary foreign domain and then back to mine for authentication. Without a workaround (that I've coded and it works) for the session restorage, the session gets lost and the process breaks.
Even though I have a working workaround; I wondered if it is not possible to open the redirect page in a new tab via js (because the redirect has to work in js at the current stage anyway), confirm the payment, then, when the payment gets confirmed, close the banking tab and do the according refreshes on the platform tab. Is this possible via js ? The problem I see with the linked solution is:
btn.onclick = () => {
const win = window.open(
'http://www.stackoverflow.com',
'Secure Payment');
const timer = setInterval(() => {
if (win.closed) {
clearInterval(timer);
alert('"Secure Payment" window closed!');
}
}, 500);
}
How can I know when the client finished the authentication in the other tab, + prevent the redirect that will automatically triggered in that case, to the redirect target post-authentication that you normally provide when requesting the payment? Is there a way to track all of this in js? Because I don't see any...?
I have an ember application where users are stored in a MySQL database. When a user exits (ie. closes their browser window), they need to be deleted from the database. I have the following code in one of my route files:
setupController: function () {
$(window).on('beforeunload', () => {
this.get('currentUser').delete();
});
},
In my testing this only seems to delete the user from the database maybe 70-80% of the time, and somehow it seems to be random whether it works or not. I'm guessing this is because sometimes the function isn't run in time before the browser has closed the window. How can I ensure the code to delete a user is executed every time a user exits?
It wouldn't work this way. Reason: browser interrupts any requests (even ajax) to backend when user closes window/tab.
I suggest to implement cleanup on backend side. What you need is store last time when user performed some action and delete those who did not make any requests in some period of time (for example, if there was no requests in 1 hour, you can be pretty sure that user closed browser window). You can also perform "ping" requests from your ember app to your backend once in a while, so idle users will not be deleted.
On my Django site, I want to logout from the site automatically when I close the tab or browser. I mean when I close the site by closing the tab instead of using logout button, after entering the URL again, I want to see that the user has already logged out from the site to force the user to enter username and password again.
Is there a way to handle closing the tab in JQuery?
Thank you in advance.
Edit: onunload & onbeforeunload events cause to logout the user when also reloading the page.
Add your logout code to the on onunload event.
window.onunload = function () {
//logout code here...
}
In JQuery you can use the .unload() function. Remember that you don't have much time so you may send the Ajax request but the result may not reach the client.
Another trick is to open a small new window and handle the logout there.
window.open("logout url","log out","height=10,width=10,location=no,menubar=no,status=no,titlebar=no,toolbar=no",true);
If you want to disable closing the window (or at least warn the user), you can use this code:
window.onbeforeunload = function(event) {
//if you return anything but null, it will warn the user.
//optionally you can return a string which most browsers show to the user as the warning message.
return true;
}
Another trick is to keep pinging the client every few seconds. If no reply comes back, assume the user has closed the window, browser has crashed or there is a network issue that ended the chat session anyway. On the client side, if you don't receive this ping package, you can assume that network connection or server has a problem and you can show the logout warning (and optionally let the user login again).
You can use Javascript onunload & onbeforeunload events. In these events destroy the session cookie for Django.
Those events are also fired when you leave a site over a link or your browsers back button so be careful and think twice if this is really what you want.
I just ran into this. In your Django settings.py file, you can add the flag:
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
This will log the user out when the browser is closed. Note that the user will remain logged in if there are other tabs or windows still open (the browser must be completely closed).
window.onunload = function () {
//logout code here...
window.open("logout url","log out","height=10,width=10,location=no,menubar=no,status=no,titlebar=no,toolbar=no",true);
}
This code works.
this will open a small pop up window for the logout url.
I would like to keep track of how long visitors spend reading a page. If they tab away, or minimize the window, time should not count towards the time on page until they look at the tab again.
I assume some combination of javascript and server side work will be necessary.
A couple of issues I'm struggling with:
What's the best way to store this information in the database?
How do I, with Javascript, capture the time on page with a reasonable degree of accuracy? Do I store events like "page loaded", "user idle", "user returned", "page unloaded", and then separately process all the events in the DB to come up with a time on page?
I've put some work into a small JavaScript library that times how long a user is on 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 ignores time that a user switches to different tabs, goes idle, minimizes the browser, etc. The Google Analytics method suggested has the shortcoming (as I understand it) that it only checks when a new request is handled by your domain. It compares the previous request time against the new request time, and calls that the 'time spent on your web page'. It doesn't actually know if someone is viewing your page, has minimized the browser, has switched tabs to 3 different web pages since last loading your page, etc.
https://github.com/jasonzissman/TimeMe.js
An example of its usage:
On loading your page:
document.onload = function() {
TimeMe.setIdleDurationInSeconds(30);
TimeMe.setCurrentPageName("my-home-page");
TimeMe.initialize();
}
Retrieving time spent on the page, and sending it to your server when the user leaves your page:
window.onbeforeunload = function (event) {
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","ENTER_URL_HERE",false);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
var timeSpentOnPage = TimeMe.getTimeOnCurrentPageInSeconds();
xmlhttp.send(timeSpentOnPage);
};
First, you need to detect when a user has moved away from a tab or is inactive. When this happens, start a timer, when they come back, stop the timer. Counting time with setTimeout/setInterval can be innacurate because of blocking, so I made myself an accurate javascript timer based on the actual difference in datetime: https://gist.github.com/4600726
So your code would look something like this:
timer = new Timer;
window.addEventListener('focus', function() {
timer.start();
}, false);
window.addEventListener('blur', function() {
timer.stop();
// send timer.msecs() to the server maybe??
// if so, also call timer.reset();
}, false);
window.addEventListener('beforeunload', function() {
timer.stop();
// send timer.msecs() to the server via jquery post, or better yet websocket
}, false);
Then you can get the elapsed time with timer.secs(). I guess it depends on your preference how often you want to send info to the server. You could do it on blur.
Another option could be to decree that no mouseover means inactivity. Start the timer and then do a setTimeout, then on the window's mousemove event cancel the setTimeout and start another setTimeout , after which you stop the timer.
As far as sending data to the server, I'd probably opt for sending it on blur and of course beforeunload. My preferred method would be with socket.io since it is fast and always connected, so you could use it to track lots of user events in real time, but you could just to an ajax call to your server. If you just send them as mini user sessions, { user: userId, page: pageId, elapsedTime: msecs } then you could then aggregate the data on the server end when you are doing analysis.
So, my current task involves a site where people can sign in, and view a series of training videos on a particular topic. I developed this within CodeIgniter. The only trouble is that once I have them log in, and I create a session, that session seems to mysteriously disappear after a few minutes, and they're mysteriously bounced back to the login page (which is what happens if someone is on the training video page without being signed in. This is the block of code in my config.php page:
$config['sess_cookie_name'] = 'cc_session';
$config['sess_expiration'] = 0;
$config['sess_expire_on_close'] = FALSE;
$config['sess_encrypt_cookie'] = FALSE;
$config['sess_use_database'] = TRUE;
$config['sess_table_name'] = 'cc_sessions';
$config['sess_match_ip'] = TRUE;
$config['sess_match_useragent'] = TRUE;
$config['sess_time_to_update'] = 3000000;
Why is sess_time_to_update set so high? At first, I thought that was the culprit, updating the session after 5 minutes. I have set the session to record to a database, and all that good stuff. Please, ask me questions, and help me get to the bottom of this!
I should point out that I have an iFrame that is on the course page that is sending a "ping" back to a server this way...
<iframe id="timerAddEnd" style="display:none;" src="http://www.example.com/course/finish/<?=$course->intKey?>/ping" >
</iframe>
<script type="text/javascript">
var auto_refresh = setInterval( function ()
{
var iframe = document.getElementById('timerAddEnd');
iframe.src = iframe.src;
}, 60000);
// refresh every minute
</script>
Could THIS be the culprit? I was hoping this would be a quick and dirty fix to the initial problem.
Are you using Firefox and Firebug with extensions (like FirePHP) installed? Because if you are having such a setup, when you open/close the Firebug console, the user-agent string changes, and your session is no longer recognized by CI.
My workaround was to disable FirePHP. Try checking your user-agent string and see if you have something extra besides the default browser user-agent. You should be able to identify it easily. if there is one.
Well, this may not be a full "answer" per se, but I did come up with a workaround of sorts.
I knew that the problem involved CodeIgniter handling sessions with... how do I put it... stuff running in the background. Originally I was using a CI page within the iFrame. Those "pings" back to the system were what was causing the lockout. So, I now use a regular, flat ol' PHP page within the iFrame. It connects to the database, but doesn't go through CI to do it. I get my "pings" to the table in question, but I don't break the session.
I had the same problem with session data getting "randomly" destroyed in CodeIgniter and I spent alot of time finding out what was wrong. Now I think i found MY problem, and it seemed as the $this->session->set_flashdata was the culprit.
I noticed that I got logged out on pages where this were used. I also noticed that if you do:
$this->session->set_flashdata('thisItem', 'value');
and later on the same page have the same variable again:
$this->session->set_flashdata('thisItem', 'new value');
then it will destroy the session data every time. Now I removed all the set_flashdata from my site, I havent been logged out since.. hoping this was my problem. When I have the time I will try to rewrite my flashing system to maybe something like if (!isset('thisItem)) { set it; } and stuff like this to prevent it from happening again, because I really want the flash messages.