How do I create an jquery script to automatically log out the user after a set period of inactivity? Or is there a jquery plugin that does this? It would need to do something like:
Create timer with setTimeout (eg for 30 mins)
Reset the timeout every time the user interacts with the page
After the setTimeout expires, use ajax to call the /logout action on the server (asp.net mvc)
Show a modal/lightbox dialog telling the user to login again
You have couple of different aspects that you need to consider here. First of all, what happens if the user just closes the browser or if the computer the person is using dies? If the user visits the page within 30 minutes, should the person still be logged in?
Let's say that the user should be logged in for 30 minutes, no matter what. The easiest way to start is to set a cookie timeout on an authentication cookie. Remember to update the timeout when each page refreshes. And use a jQuery timer to check if the cookie is still valid or not, or just keep track of the users login time.
So, jQuery timers, you could on each page load refresh the cookie and then just check if the timer/delay executes, if so, remove the cookie and display a modal box.
There's tons of ways of doing this, using the timers are one way.
$(this).oneTime(1800 , function() {
location.href='/logout'; // redirects to logout page.
});
Another aproach is to use server side checking for this, but you will not get the model box for this, as I said, there are tons of ways, it all depends on your preferences.
I know it's very old question, but could be useful for someone looking for similar solution to log out user if they are idle for certain timeperiod
http://www.dotnetfunda.com/articles/show/3130/automatically-logout-when-user-is-idle-for-sometime
The link may disappear so here is the code -
<script>
$(function () {
$("body").on('click keypress', function () {
ResetThisSession();
});
});
var timeInSecondsAfterSessionOut = 30; // change this to change session time out (in seconds).
var secondTick = 0;
function ResetThisSession() {
secondTick = 0;
}
function StartThisSessionTimer() {
secondTick++;
var timeLeft = ((timeInSecondsAfterSessionOut - secondTick) / 60).toFixed(0); // in minutes
timeLeft = timeInSecondsAfterSessionOut - secondTick; // override, we have 30 secs only
$("#spanTimeLeft").html(timeLeft);
if (secondTick > timeInSecondsAfterSessionOut) {
clearTimeout(tick);
window.location = "/Logout.aspx";
return;
}
tick = setTimeout("StartThisSessionTimer()", 1000);
}
StartThisSessionTimer();
Related
Background:
Back at work, I'm working on a Web Forms App that uses default, sliding expiration for Session and FormsAuthentication time outs. My task is to track user inactivity and , if needed, display modal window with a warning about session expiration, timer and a button to refresh session time out (it would refresh forms authentication time out also). Button is wired to the event on the master page with an empty body, it does the job for now. (I'm aware of other solutions).
Partially working solution:
My approach was to use master page Page_PreRender method to get Session and FormsAuthentication time out values, compare them and pass smaller(or any) value to the client's browser (with other necessary data). In the browser, I would then display warning with the timer at some particular moment in modal window and it would all work as intended... that is...when the user is doing nothing.
Problem:
Our app has lots of pages with update panels. Those update panels are used to interact with and manipulate data stored in the Session. Whenever user does something inside one of those update panels, the session time out slides (restarts). I cannot track those things on the client (in the real world), I need a way to track Session expiration on the server.
Things I don't want to do
I dont' want go through every single page, every single gridview, every single imagebutton etc and to bind some client event to track user actions. I want more... generic and maintainable solution if possible.
My idea:
I would like to be able to track/check Session or FormsAuthentication remaining time before expiration occurs OR to be notified if those values have been reseted. That way I could have initial data on the client about the moment in time when I should display the modal window with warning, and at that time, I would like to be able to check with the server first IF that time is right (approximately) or if I should update my javascript data on the client and prolong the time before displaying warning window since the session expiration has been updated...
And what about intercepting and filtering user requests ? Would that help ?
Have you considered Session State via SQL Server? It allows you to manage sessions via the database, opening up the option to query the expiration information you desire. Check out this link. Or this link.
Implement IHttpModule, attach to appropriate HttpApplication events and in its do what you want.
Although it doesn't do exactly what you're asking for, perhaps this Timeout control might at least provide some inspiration?
*Update: There's some comments on the blog from a guy implementing the control with sliding expirations and how he made it work.
First of all, thank you all for your suggestions. I've managed to solve this problem last week, just didn't had time to post earlier... and frankly, I was interested in other solutions. I'll make sure to read all the material you posted and suggested. Thank you for that.
Here's what I did:
On the server side:
I used cookies to track session expiration time. One thing that slipped my mind was that Page goes through its whole life cycle even on asynchronous requests. The whole idea was to use Master Page's Pre_Render event to set the appropriate cookies on EVERY request.
I was using UTC time format and was calculating milliseconds that are translatable to javascript time format :
var tmpDate = new DateTime(1970, 1, 1);
var nowUtc = DateTime.UtcNow;
var tmpSpan = new TimeSpan(nowUtc.Ticks - tmpDate.Ticks);
return tmpSpan.TotalMilliseconds;
With this, I had everything I needed for my calculations, current time, session expiration (Session.Timeout) time, and time for warning... basic math from there.
On the client side:
First, I red all three cookies to start tracking up and initialized two separate variables for tracking current server time. They were both initialized to the same value of the first cookie read of the current server time.
Then, I've used setTimeout function to read cookie (current server time) every second (jQuery plug-in). I was checking if current server time from former cookie read and current server time from latest cookie read were equal(separate variables) - that way I knew if there were any requests made and if there were, I would read 2 other cookies for warning time and time-out time to update things up and close warning dialog if it was opened. After that I would make current server time variables equal and continue comparing them after every cookie read and updating only one of them.
Also, on every setTimeout call I'm getting current time with
new Date().getTime();
which returns current UTC time measured on the client machine. In any case we rely on the presumption that client has valid clock set-up on his/her machine. After that I'm comparing current time with warning time and if current time is "bigger" that the warning time and "smaller" than the time-out time, then we have to display popup.
If the current time is "bigger" than the time-out time, click invisible button that calls method in the masters page code behind that logs out user. This works great even when user has multiple tabs open in browser. Once the user is logged out in one tab, every other page(tab) that tries to log him out also, gets redirected to login page.
If the user click OK button to confirm his/her presence, an empty event in masters page code behind is triggered (click hidden asp button). This is enough to refresh the session. This will automatically resend cookies, and everything goes as intended. (given that you have sliding session).
It was easy to implement timer in the warning window. I've dynamically created div for modal window with message and 3 spans. On every setTimeout iteration I was setting timer like this:
Calculate Hours, Minutes, Seconds from current javascript time
Place result in variable
If the result is smaller than 10 then prepend 0 (zero)
Target appropriate span by class(had problems with ID in IE 8, used unique classes) and set its text property to the calculated value $(obj).text(calculatedValue)
For The End
Make sure that, when you are reading cookies to parse them as floats, just to be sure.
I'm interested to see the application of server push technology and usage of web sockets in this particular situation but I think it would be an overkill if you would track and calculate session expiration on the server for every client.
I know that I've asked for session expiration tracking on the server and that this looks like tracking on the client, but it's not... those cookies are all we need for tracking and they come from server so... that's about it.
Here is my solution.
Ensure that FormsAuthentication.CookieMode is set to use cookies (it is by default).
Add new key to Session object and populate it in each page request (master-page's events like Page_Init, Page_Load etc.), include postbacks and callbacks.
Session["SessionUserLastPageRequestTime"] = MyApp.CommonUtils.GetServerDateTime();
Create a HttpHandler, which implements IReadOnlySessionState interface.
public class SessionStateHandler : IHttpHandler, IReadOnlySessionState
Place the SessionStateHandler haldler into folder with allowed anonymous access (or just put it to root folder).
public void ProcessRequest(HttpContext context)
{
string requestData, alertMessage;
using (var reader = new StreamReader(context.Request.InputStream))
{
requestData = reader.ReadToEnd();
}
/* -1: unauthorized;
* -2: authorized, but no information about last request time;
* -3: more than half session timeout, or not needed to inform user about session expiration;
* >=0: lesser than half session timeout or if needed to inform user. The number reflects the value of total amount of minutes to session expiration.
*/
int status = -1, idleTimeInMinutes = 0;
if (context.User?.Identity == null
|| !context.User.Identity.IsAuthenticated
|| context.Session == null
|| context.Session["SessionUserLastPageRequestTime"] == null)
{
status = -1;
alertMessage = "Session expired!";
}
else
{
DateTime now = MyApp.CommonUtils.GetServerDateTime();
var userLastPageRequest = (DateTime?)context.Session["SessionUserLastPageRequestTime"];
if (userLastPageRequest == null)
{
status = -2;
alertMessage = null;
}
else
{
var halfTimeout = TimeSpan.FromMinutes(context.Session.Timeout / 2);
TimeSpan idleTime = now.Subtract(userLastPageRequest.Value);
idleTimeInMinutes = (int)idleTime.TotalMinutes;
if (idleTime <= halfTimeout)
{
status = -3;
alertMessage = null;
}
else
{
status = context.Session.Timeout - idleTimeInMinutes;
/* Send time to session expiration only if 3 or lesser minutes remain */
if (status > 3)
status = -3;
/* If session expiration time's expanding (sliding expiration) has been done in some way */
else if (status < 0)
status = 0;
alertMessage = string.Format("Session Will Expire In {0} Minutes", status);
}
}
}
context.Response.Write(JsonConvert.SerializeObject(new { Status = status, Message = alertMessage }));
/* Remove new cookie to prevent sliding of session expiration time */
if (requestData == "TIMEOUT_REQUEST")
context.Response.Cookies.Remove(FormsAuthentication.FormsCookieName); /* by fact FormsAuthentication.FormsCookieName equals to ".ASPXAUTH" */
}
Note that server will slide session expiration only if request is detected after at least half of session timeout time is gone since session start, e.g. if Session.Timeout is set to 30min, new cookie with ticket will be send to client in response on first request after 15min since session start.
So as far as you want to KNOW the session expiration time, and not to EXTEND it instantly, then you need to remove new ASP.NET auth. cookie from response (look at line context.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);).
Create continious request from client side by using setInterval or setTimer
var stc_ContiniousRequestOfSessionState_IntervalId;
function stc_ContiniousRequestOfSessionState() {
stc_ContiniousRequestOfSessionState_IntervalId = setInterval(stc_ContiniousRequestOfSessionState_OnInterval, 20000);
}
function stc_ContiniousRequestOfSessionState_OnInterval() {
stc_RequestSessionStateFromHttpHandler("TIMEOUT_REQUEST");
}
function stc_RequestSessionStateFromHttpHandler(dataToSend) {
var url = '<%: Page.ResolveClientUrl("~/handlers/SessionStateHandler.ashx") %>';
$.ajax({
type: "POST",
url: url,
contentType: "application/json",
dataType: "json",
data: dataToSend,
success: function (result) {
stc_sessionState = result.Status;
if (stc_sessionState == -2 || stc_sessionState == -3) {
hideSessionEndWarningMessage();
}
else if (stc_sessionState == -1) {
sessionExpired = true;
clearInterval(stc_ContiniousRequestOfSessionState_IntervalId);
showSessionTimeoutWarningMessage(result.Message);
}
else if (stc_sessionState >= 0) {
showSessionTimeoutWarningMessage(result.Message);
}
},
error: function (result) {
/* we can increase request frequency, re-send session request instantly or do something else at this place */
}
});
}
run JS function on page load by adding it to startup scripts on master-page.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Page.User.Identity.IsAuthenticated)
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "test1", "continiousRequestOfSessionState();", true);
}
}
}
I am trying to get a list of active session id's in my web application.
I tried to manage a list in Global.asax.
I add session id when Session_Start is fired, and remove session id when Session_End is fired.
The problem is in cases when the user closes the browser or shut down the computer.
The Session_End is not fired, and the seesion still exists in the list.
Somebody has an idea how can I get the list?
Thanks!
There is no solution to this problem that avoids the complication you note. Unless there is some explicit way to end a user's session - and the user activates it - the only way to know when a session has ended is to allow it to expire.
Session_End will eventually fire, when the session times out. The only time you never see Session_End called is when the application domain itself unexpectedly quits. In such a case, you know that all of your sessions are dead, anyway.
Andrew Barber is correct. There is just one more thing you can do:
Ask your users to logout. In fact not just ask them but in a way force/remind them that they have to log out.
Here is how i did it:
<script type="text/javascript">
$(function () {
$("a").click(function () {
window.onbeforeunload = null;
});
});
</script>
<script type="text/javascript">
window.onbeforeunload = confirmExit;
function preConfirm() {
if ((window.event.clientX < 0) || (window.event.clientY < 0)) {
confirmExit();
}
}
function confirmExit() {
return "You have attempted to leave this page. It is suggested to log out using the link. Are you sure you want to exit this page?";
}
</script>
By adding these scripts to your master page (if that is the case or in every page) the browser prompts the user with a modal window with your message if they try to load another page or close the browser without logging off.
Of course the user my decide to leave the page anyway even though you remind him to log off but really you have tried your best!!
If you use a SQL Server database to store your sessions in it becomes easier to retrieve what appears to be currently active by using an SQL query to get what you need.
I say appears because like others have noted sessions can hang around if they are not properly cleared using Session.Abandon() e.g. if the user just closes their browser window without logging out. This means that you can only rely on the expiry date of the session to be sure the session is completely finished with, however long you have set that to be.
I should also point out that if you do use a database as your session store, the Session_End event will never fire.
There are various ways to handle session timeouts, like "meta refreshes" javascript on load functions etc.
I would like something neat like: 5 minutes before timeout, warn the user...
I am also contemplating keeping the session open for as long as the browser is open(still need to figure out how to do it though... probably some iframe with refreshing).
How do you handle session timeouts, and what direction do you think i should go in?
The best approach to handle sessions timeouts.
I say that there is 2 basic cases.
One is when the users enter little or no data, and just read reports, or do small thinks with his mouse. In this case there is not easy way to inform him that the session is going to expire. If you going to check the time left for the session calling the code behind, then automatically you update the session. Then if you have a timer to count down the session, then maybe the user have open a new tab of your web and the session is going to expired but not the time you have note with javascript and the user receive wrong message.
So for me, when the user enter little or no data, just let the session expired, if he lose one click, it will do it again later.
Second is when the user need to enter many data, that some time can take time, a long text for example, to write it and fix it. In this case I use the below technique and I am not let the session go out.
How to keep the session open as long as the browser.
Here is a very nice and simple technique, I use an image that I make an reload of it before the session is timeout using JavaScript.
<img id="keepAliveIMG" width="1" height="1" src="/img/ui/spacer.gif?" />
<script language="javascript" type="text/javascript">
var myImg = document.getElementById("keepAliveIMG");
if (myImg){
window.setInterval(function(){
myImg.src = myImg.src.replace(/\?.*$/, '?' + Math.random());
}, 6000);
}
</script>
In a third case, you can do this. We care if the session is expired only on post back. When the user have enter some data and on the post back the application is redirect him on the login page and the post lost.
In this third case you can capture the post data and saved them until the user re-login. You capture the post data on global.asax on the
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
This is the function that called before the redirect to the login page, and there you see if you have post data and the use required to login, you save that post data, ether to a new redirect page, ether to the server (maybe on session, maybe on your temporary database).
Now after the user is login again, you redirect him again to the last page with the saved post data, and the user is continue as it is.
The only trick here is to make a middle page, that render the form with the last posted data and an automatically redirect javascript call.
The only thing I can think of is to generate some script on the page that creates a client timer, so that when the page is received and rendered, it can show an alert X-minutes later (that is 5mins before expire).
If you'd rather have the session just keep itself alive, you can do this with a generic handler (ASHX) that you periodically call via AJAX. This will help refresh the session and it should stay alive for as long as the AJAX calls continue.
Example "keepalive.ASHX":
<%# WebHandler Language="C#" Class="keepalive" %>
using System;
public class keepalive : System.Web.IHttpHandler
{
public void ProcessRequest (System.Web.HttpContext context)
{
context.Response.ContentType = "text/json";
var thisUser = System.Web.Security.Membership.GetUser();
if (thisUser != null)
context.Response.Write("[{\"User\": \"" + thisUser.UserName + "\"}]");
}
public bool IsReusable
{
get { return false; }
}
}
And here's the script on the page to call it (with jQuery for simplicity):
<script type='text/javascript'>
function keepAliveInterval()
{
$.ajax(
{
url: "keepalive.ashx",
context: document.body,
error: function () {
alert("AJAX keepalive.ashx error :(");
}
});
}
$(document).ready(function () {
window.setInterval('keepAliveInterval()', 60000);
});
</script>
Use some jquery that keys off of your session timeout variable in the web.config. You can use this Jquery delay trick that when a specific time occurs (x number of minutes after load of the page), it pops up a div stating session timeout in x minutes. Nice, clean and pretty simple.
Regarding session timeout, Codesleuth's ajax call would be perfect.
I try to redirect my page for a logged in user with a certain amount of inactivity to a different page without killing the session.
I would like to substract the time I spent on the first page from the session, put the user on the new page, and then log the user out after his session (rest of the session time) times out and redirect the user to the login page.
I found this:
HttpContext.Current.Response.AppendHeader("Refresh", Convert.ToString(((HttpContext.Current.Session.Timeout * 2) - 5)) + "; Url=Dashboard.aspx");
but this interferes with my master page:
Context.Response.AppendHeader("Refresh",Convert.ToString((Session.Timeout * 60)) + "; URL=" + ResolveUrl("~/Logout.aspx"));
If it is easier, the user session does not need to be subtracted by the time the user spent on the first page.
Is there maybe an easy javascript out there that I missed on google?
Thanks,
Patrick
Ok, I did the following to solve this issue: Everytime a user hits a button, i call detime(), and also on the page_load I call detime(). Maybe not the best solution, but at least I got what I want ;)
function timer()
{
time1 = window.setTimeout('redirect();', 300000);
}
function redirect()
{
window.location = "XXX.aspx";
}
function detime()
{
if (time1 !=null) {
window.clearTimeout(time1);
time1 = null;
}
timer()
}
Well, I suppose it depends on your server platform, but in my experience it's the server that determines session timeout. The reload that your client-side code triggers will, unless you somehow override the normal behavior of the server, refresh the session and start the timer over again.
Now, what you could do is update the page client-side and not talk to the server at all. To do that, you'd effectively load the code to the "almost timed out" page at the same time you load the original page. Then, when your timeout fires, you just show the desired page and hide whatever's there.
I would encourage you to consider the usability issues with this overall scheme.
It seems like what you want to do is pass a timestamp along with the redirect and then capture the timestamp and either use that or, if its undefined, the current time as the time the user started. Then once that time has run out send the user to an explicit log out that kills their session.
As long as you redirect to a page that explicitly kills the session, I don't think you'll have a problem with expiration. Accept in the case where the user gets redirected to the new page, and then closes the browser, which maybe you could use an onunload script to kill the session explicitly again.
When the user clicks on a link to generate report I make an AJAX call which generates a pdf file in the background.Now the files are huge running upto 10mb or more.So it takes some time.In the mean time the user should be able to navigate other links as if nothing has happened.So I need to implement in such a way that the pdf generation process gets started & user doesn't have to wait for the process to finish.Is this possible?I am using AJAX Pro with c# with dot net framework 2.0
The problem here is that as soon as the AJAX activity begins the browser enters into a hung stage & the user has to wait although he clicks on a different link.
I would probably create a 'queue' or an 'inbox' for the user ...
start your pdf generation routine with a ThreadPool.QueueUserWorkItem (you would also need to modify your generation method to output to their inbox)
then on each http request check that inbox and notify the user of the item ... you can always poll the server on an interval or somthing
Sure, but once the user navigates to another page, the Javascript that is waiting for the Ajax response is no longer running, so that request is lost. You'd have to either find a way to keep that page open (using frames or exclusively Ajaxified navigiation), or find a way to store the response and notify the user of its completion on the next page view. For instance, storing a session variable that indicates that the operation is completed, or storing it in a database with (perhaps) an "unread" boolean value.
You can have asynchronous Ajax call with which you can do other tasks while response objects returns from the Ajax page.
Here is some example, testAjax.aspx is the Ajax page here :
http_request.onreadystatechange = function() { alertContents(http_request); };
http_request.open('GET', 'testAjax.aspx?', true);
http_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http_request.send(null);
function alertContents(http_request)
{//debugger;
if (http_request.readyState == 4)
{
if (http_request.status == 200)
{
var vResult;
vResult=http_request.responseText;
//Write your logic after successful Ajax call here.
}
else
{
alert('There was a problem with the request.');
}
}
}