I need to kill the session when the user closes the browser or redirects into some other page.
I can see the following options of achieving this functionality:
Use no session login. It's not my case, because I'd have to change a lot and I also use sessions for some other data.
I could use something like this:
window.onunload = window.onbeforeunload = (function () {
...
})
And from this code call the action that cleans the session and performs logoff.
Sounds nasty but what is also important - this JavaScript code works only in IE.
I could create some nasty code that uses some dummy calls, let's say every minute, just to say the server that the user is still alive.
But it's really nasty. It would use useless load on the server, lots of useless calls and in the case if some call was lost(because of the connection issue or something) the user would logg off.
Any other options?
You've left off #4: Don't do anything, have sessions time out after a reasonable period (say, 20 minutes); if they try to do something on that page after being gone for 20 minutes, just show a page telling them their session has expired and to log in again. That's usually the simplest option.
If you don't want to do that, #3 is really your only viable option, but once/minute is probably overkill. Set the session timeout to 20 minutes, remember when the user has done something, and if they're idle for (say) 15 minutes do a proactive call on their behalf. But even then, I'd limit how much I'd do this, after a couple of hours you might want to just redirect them to the login page.
I think this answer is the right way to go:
In javascript, how can I uniquely identify one browser window from another which are under the same cookiedbased sessionId
Set a unique window id:
window.windowIdClient = "{978d-478ahjff-3849-dfkd-38395434}"; //or another randomly generated id.
Store that windowId in the database, along with the ip-address and the session-id. If those three do not match than the user is logged out.
In addition, if didn't think of T.J. Crowder's option, I use it myself.
Related
I have a dashboard page, where I have some time values that come back from the server. These times are in the format: HH:MM:SS (13:05:01, for example). But that value only refresh when then user reloads the page. I would like to do some javascript to keep that value going on... what's the easiest easy to do that? Thanks in advance!
Can you give me a valid reason to spam the servers with requests for time over and over again when the user machine has high probability of having perfectly valid time - is connected to internet and unless user has not messed with it it's correct.
(You might have to offset for zones, not 100% about that)
Downsides of approach to ask server over and over for current time:
You will suffer from latency
You will spam server without valid need
Ability to scale is sinking very fast both by items and users
If you need to check user time matches yours, do a 1 request at the start and then compare times with a bit of offset allowed. If times don't match set the correct time on front from back and display user device time +- whatever the difference was. If they match close enough display user's device time.
Deletes all the negatives. Adds no new negatives.
EDIT upon comment:
Oh, that makes more sense. You can query server on reload but if you expect to reaload a lot (and you need a time to be static after once being set up) you can use localStorage to store it on new browsers or cookies (work for older browsers as well).
For something that is not likely to change I would not query the server again if I don't need to. In case you need / wanna query the server again specifficaly when page loads or reloads you can add this to element on that page onload="myFunction()"
In myFunction handle to call to the back and binding to text of element displaying it.
Personally, I would go about doing it with setInterval, just set it to run the function that updates your time, and set the interval, to 1000 (milliseconds) for it to change every second. You can look Here for more info.
I've got an application that I intend to set a lock flag in my database that would exclude others from viewing that same page if set.
However, once set - I have no idea how to "unset" it. I could make it up to the user to unset the flag, but that seems unnecessary.
I'd want to simply look for the browser to leave the page, make a call to the database, and unlock the page.
How does one do this "type" (not looking for the exact way) of thing with JSF/Javascript/jQuery (all options)
There's really not a reliable way to do this, that I've seen anyway.
You can use the browser's onbeforeunload event to tell the server, "Hey I'm leaving the page now.". The issue is you can't actually block the page from unloading. If the user is actually closing the browser, any open sockets are going to be closed immediately. Your web server may or may not get the request in time. I've had very flaky results with this approach.
One approach that might work is to employ some sort of timeout mechanism. The page would ping the server every 30 seconds or what not, saying "I'm still here." If the server did not get this update after a few minutes, it would invalidate the session and free up that document. Perhaps this could be optimized by checking for the last ping when someone new came along. One issue with this is if someone left the page, the next user might have to wait a minute or two before they could go to the page. You'd then have to find a ping frequency that doesn't flood your server with traffic, but also doesn't make the next user have to wait too long.
It's also possible to combine these two methods. When the user leaves the page, trap the onbeforeunload event and immediately invalidate the session. However, if it didn't work, the session would time out after a minute of not being pinged.
Are there better solutions?
If you really need to lock a document in a web app so multiple users can't edit it, you might want to investigate your overall design. Are you afraid of users clobbering data? If so, maybe employ a mechanism that can resolve merge conflicts, or detect if both sets of changes can be combined.
If you wanted to go truly Web 2.0, you could design something similar to Google Docs, where changes appear live as they're made. No need for a Save button anywhere!
Sending a "keep-alive signal" might be an option. Something along these lines on the frontend side, combined with session cookies.
setInterval(function() {
var img = new Image();
var src = "http://examle.com/keepalive.gif?cachebuster=" +
Math.ceil(Math.random() * 10000 );
}, 1000);
Is there a way to bind a jQuery event to pop off after a visitor holds a button for more than, say, 3 seconds? In this case I'd like to do something after a user holds f5 for 3 seconds.
I've found a solution that prevents the refresh when user presses f5 here:
Disable F5 and browser refresh using javascript
However, this isn't quite what I'm looking for as I'd like to allow my users to refresh pages but prevent them from placing a rock on the f5 button so to speak (it's an online game where you can do tasks by refreshing the page).
Is what I'm trying to do even possible?
EDIT: I am looking for a short-term, quick, client-side fix. The server side of things will be solved later on.
This is the kind of problem you really need to solve server side. If the task can be accomplished by refreshing the page, then it can be accomplished by a bot or a line-or-two of script that disables your check. Doing this client side won't really help you.
All you need to do in that case is on the users session, track the last time that action X was performed, and don't perform it again unless more than Y seconds have passed, and tell the user off for trying to do it too fast.
Edit: As a quick hack, what you could possibly do is configure your webserver to supply a cache-control header in the response for affected scripts with a value set to have the content expire in Y seconds. This may (emphasis on may, test this properly first!) prevent the client from re-requesting the page on a normal 'F5', however a force refresh (ctrl+f5 in some browsers) won't be affected by this.
Although again if the issue is that users are exploiting this issue, fixing it client side won't work for very long and users will quickly discover another way around.
PhonicUK's answer (do it server side) is the only correct way to handle this. But you said in a comment on that answer:
I was just asked to apply a quick client-side fix for now. That's why I'm asking if it's possible.
It's possible to do something that will get bypassed, like this (here I'm assuming you use a jQuery cookie plugin):
(function($) {
$(document).on("keydown", function(e) {
var lastRefresh, now;
if (e.which == 116) {
now = new Date().getTime();
lastRefresh = $.cookie("lastRefresh");
if (lastRefresh && (now - parseInt(lastRefresh, 10)) < 3000) {
e.preventDefault();
}
$.cookie("lastRefresh", now);
}
});
})(jQuery);
Again, though, the users will find a way around it.
Be sure to run the script through the Closure compiler or a really good obfuscator. :-)
I have an ajax heavy website that breaks (or shows incorrect data) when users have it open in multiple browser windows at the same time. So I would like to enforce only allowing the user to be logged in to the website in one tab at a time, whether it is on the same computer or even multiple computers.
I am looking for ideas on how to do this.
Is there any JavaScript method to tell if a certain page is already open in another tab?
Perhaps there is another solution that could involve the server side..
For instance, the client could message the server every say, 1 minute. If the server gets messages from a certain users at a frequency higher than one message per minute, it knows that it is open in more than one window or tab. It can then let one of the clients know that it needs to shout an error to the user.
The idea of messaging the server every one minute does not sit that well with me though.
Any other ideas out there?
EDIT: some people are wondering why I have this problem in the first place. Here it goes:
This is a time tracking application that is fully ajax. You can browse/create/delete/modify timers, projects and clients with ajax, without ever leaving the page. If the website is open in multiple tabs, things will get inconsistent very quickly. Errors usually even occur. For instance, user creates a project and then starts a timer in tab1, tab2 will not show these changes. And since it is all ajax, it will not simply sync when the user clicks some button in the second tab.
Having read the update in your question, what I would really suggest is using WebSocket where available, falling back to Flash socket, long polling and forever iframe for older browsers (actually I'd use Socket.IO to make it all easy - you can use a similar abstraction for whatever environment you are using). That way you can make all of your windows and tabs consistent in real time - problem solved.
That having been said if you don't want to do it for some reason (though what you are trying to do would be a perfect application for WebSockets so think about it) you might use sessionStorage and localStorage to distinguish sessions between tabs or windows for the same logged in user, but it is not widely available yet - see the compatibility table so it would be probably easier to go real-time with a socket.io-like solution where there are a lot of fallbacks available than to restrict visitors to one tab - not to mention the user experience.
There's no way to get information about other tabs/windows in javascript (and for good reason).
The best way I can think to do it would be to print a unique identifier (a timestamp should work reasonably well) in the javascript code for each page, and then it periodically ping the server with that unique ID, and associate it on the server with the user. This way if you have more than one ID belonging to a single user being pinged within a given interval, you can send back a response to the page to warn the user that having multiple tabs open will result in unexpected behavior.
(Like Caspar said above though, you should really figure out why the unexpected behavior is happening and fix that rather than force the user to act a certain way)
This is pretty lo-fi, but I think the simplicity may make it work: you could try having the login open the session in a named window (or change the name of the current window). Then, on load inside the application, check to see if the browser window name is the one you've allowed them to use; if not, pop up an alert, close the window, focus on the named window, if still there. (If not there--i.e., they've already closed the other window--you could let this one stay open, and change the name to the correct name.)
So you're essentially using window.name and window.opener. Rough idea, but an idea.
I have a similar situation and the solution I use is:
on server: at every login you create an unique ID, save it (ex. database) and return it to client.
on client: on every transaction you send this ID to server as a parameter.
on server: if saved and received ID match then allow the request to execute if not refuse it with an error code.
on client: if transaction failed with specific code then you know that "ID" verification failed and you logout user.
So in this way if the same credentials will be used again in any other tab, browser, PC, country,... the old tab will logout user on next transaction request. Or in other words limiting only one opened page per user on the whole world.
Edit:
As I have stopped using html requests for any data communication and use websockets, I register user on server and if same user wants to login from some other location I close the previously used socket (the page automatically logs out).
In this way I also have a way to trigger full page reloads from server in case admin does something that influences users.
Simply use cookies.
$(window).on('beforeunload onbeforeunload', function(){
document.cookie = 'ic_window_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
});
function validateCallCenterTab() {
var win_id_cookie_duration = 10; // in seconds
if (!window.name) {
window.name = Math.random().toString();
}
if (!getCookie('ic_window_id') || window.name === getCookie('ic_window_id')) {
// This means they are using just one tab. Set/clobber the cookie to prolong the tab's validity.
setCookie('ic_window_id', window.name, win_id_cookie_duration);
} else if (getCookie('ic_window_id') !== window.name) {
// this means another browser tab is open, alert them to close the tabs until there is only one remaining
var message = 'You cannot have this website open in multiple tabs. ' +
'Please close them until there is only one remaining. Thanks!';
$('html').html(message);
clearInterval(callCenterInterval);
throw 'Multiple call center tabs error. Program terminating.';
}
}
callCenterInterval = setInterval(validateCallCenterTab, 3000);
}
In my web app, when a user logs in, I add his Id to a vector of valid Ids in the servlet, when he logs out, I remove his Id from the vector, so I can see how many current users are active, if a user forgets to log out, my servelt generated html has :
<meta http-equiv="Refresh" content="30; url=My_Servlet?User_Action=logout&User_Id=1111">
in the tag to automatically log him out.
But I've noticed many users are there for ever, never logged out. I found out why, by closing their browsers, they never manually or automatically logged out, so their user Ids will never be removed from the valid user Ids vector.
So, my question is : how do I detect users closing their browsers, so my servlet can remove their Ids from the vector ?
I see some light at the end of the tunnel, but there is still a problem, my program has something like this :
Active User List :
User_1 : Machine_1 [ IP_1 address ]
User_2 : Machine_2 [ IP_2 address ]
User_3 : Machine_3 [ IP_3 address ]
...
How do I know, from the session listener, which user's session has ended and therefore remove him from my list?
I was hoping when the session ends, the HttpServlet's destroy() method would be called and I can remove the user Id in there, but it never gets called when user closes his browser, why? And is there any other method in the HttpServlet that gets called when a session closes?
There is no way to know on the server-side (unless you are using some JavaScript to send a message to the server) that the browser has closed. How could there be? Think of how HTTP works - everything is request and response.
However, the application server will track when Sessions are active and will even tell you when a Session has been destroyed (such as due to time-out). Take a look at this page to see how to configure a HttpSessionListener to receive these events. Then you can simply keep track of the number of active sessions.
The number of active sessions will lag behind the actual number of current users, since some period of (configurable) time has to elapse before a session is timed out; however, this should be somewhat close (you can lower the session-timeout to increase the accuracy) and it is a lot cleaner and easier than 1) tracking Sessions yourself or 2) sending some asynchronous JavaScript to the server when a browser is closed (which is not guaranteed to be sent).
I suggest you remove the ID when the Servlet engine destroys the session. Register a HttpSessionListener that removes the user's ID when sessionDestroyed() is called.
Diodeus's idea will only help you detect that the session is over more immediately.
in JavaScript you can use the onbeforeclose event to pass a call back to the server when the user closes the browser.
I typically use a synchronous Ajax call to do this.
I had to do that recently, and after some searches, I found some solutions on the Net... all of them non working universally!
onbeforeclose and onclose events are used for this task. But there are two catches: they are fired when the user reload the page or even just change the current page. There are tricks to see if the event is actually a window/page/tab closing (looking at some Dom properties going haywire on closing event), but:
They are browser dependent
The tricks are undocumented, thus brittle
And actually they vary along the browser version/update...
And worst of all, these events are now ignored by most modern browsers, because they have been abused by rogue ads popping out windows when browser was closing. They are not fired in Safari, Opera, IE7, etc.
As pointed out, most Web applications with login destroy the user session after a while, eg. half an hour. I was asked to logout on browser closing to free faster a precious resource: licenses. Because users often forget to log out...
The solution I gave was to ping with an Ajax request (sending the user ID) the server on regular intervals (say 1 minute). If the server receives no ping for, say, 3 minutes, it disconnect the user.
There is no foolproof way to do what you're trying to do, but both sblundy and Diodeus have plans that will cover most circumstances. There is nothing you can do about someone who turns off Javascript in their browser, or their internet connection goes down, or their power goes out. You should just cull sessions after a certain period of inactivity (which I think is what sblundy's suggestion of listening for session destruction will do).