If the session has expired and the user clicks on a link to another webform, the asp.net authentication automatically redirect the user to the login page.
However, there are cases when the user does not click on links to other webforms. For example: edit link in gridviews, when using AutoCompleteExtender with textboxes and the application attempts to get the information, and basically, in every case when a postback is done and the event is not automatically handled by the asp.net authentication.
What is the best way to handle these exceptions?
UPDATE: I have just modified the question title: forms authentication timeout, instead of the initial session timeout. Thanks for making me aware of this difference.
UPDATE: I have just created a new question with the specific problem I am facing: How to handle exception due to expired authentication ticket using UpdatePanel?. Surprisingly, I have not found much information about it. I would really appreciate your help.
This is why many systems include timers on the page to give approximate timeout times. This is tough with interactive pages. You really need to hook ajax functions and look at the return status code, which is a bit difficult.
One alternative is to use code based on the following which runs early in the page lifecycle and perform an ajax redirect to a login page. Otherwise you are stuck trying to intercept the return code from ajax and in asp.net where the ajax is done 'for you' (ie not a more manual method like jQuery) you lose this ease of detection.
http://www.eggheadcafe.com/tutorials/aspnet/7262426f-3c65-4c90-b49c-106470f1d22a/build-an-aspnet-session-timeout-redirect-control.aspx
for a quick hack you can try it directly in pre_init
http://forums.asp.net/t/1193501.aspx
Edit
what is wanted are for forms auth timeouts, not session timeouts. Forms auth timeouts operate on a different scale than session timeouts. Session timeouts update with every request. Forms auth tickets aren't actually updated until half of the time goes by. So if you have timeouts set to an hour and send in one request 25 minutes into it, the session is reset to an hour timeout, the forms auth ticket isnt touched and expires in 35 minutes! To work around this, sync up the session timeout and the forms auth ticket. This way you can still just check session timeouts. If you don't like this then still - do the below and sync up the timeouts and then parse the auth ticket and read its timeout. You can do that using FormsAuthentication.Decrypt - see:
Read form authentication cookie from asp.net code behind
Note that this code requires that upon login you set some session value - in this case its "UniqueUserId". Also change the login page path below to fit yours.
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
//Only access session state if it is available
if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
{
//If we are authenticated AND we dont have a session here.. redirect to login page.
HttpCookie authenticationCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authenticationCookie != null)
{
FormsAuthenticationTicket authenticationTicket = FormsAuthentication.Decrypt(authenticationCookie.Value);
if (!authenticationTicket.Expired)
{
if (Session["UniqueUserId"] == null)
{
//This means for some reason the session expired before the authentication ticket. Force a login.
FormsAuthentication.SignOut();
Response.Redirect("Login.aspx", true);
return;
}
}
}
}
}
If you're using Forms Authentication, the user will be redirected to the login page when the Forms Authentication ticket expires, which is not the same as the Session expiring.
You could consider increasing the Forms Authentication timeout if appropriate. Even to the extent of using a persistent cookie. But if it does expire, there's no real alternative to redirecting to the login page - anything else would be insecure.
One way to deal with Session timeouts is to use Session as a cache - and persist anything important to a backing store such as a database. Then check before accessing anything in Session and refresh if necessary:
MyType MyObject
{
get
{
MyType myObject = Session["MySessionKey"] as MyType
if (myObject == null)
{
myObject = ... get data from a backing store
Session["MySessionKey"] = myObject;
}
return myObject;
}
set
{
Session["MySessionKey"] = value;
... and persist it to backing store if appropriate
}
}
If you're using a master page or a base page, I would add some logic to one of the events in the page lifecycle to check whether the session is new:
protected void Page_Load(object sender, EventArgs e)
{
if (Session.IsNewSession)
{
//do whatever you need to do
}
}
Related
My MVC web application uses asp.net session management. Session has default timeout 20mins. On session timeout, user is redirected to the home page. My application uses SessionTimeout ActionFilterAttribute to handle session timeout.
SessionState is stored in server.
Problem:
Even if the session timout happens, when the user returns to a particular action method, I need to renew a session for that user and allow to continue instead of redirecting to home page.
I have tried to use the OnActionExecuting method in the SessionTimeout ActionFilterAttribute to identify the session timeout & if the action in the request is that particular action method, then allow the user to continue to that action.
But it seems to be not working. It just redirects the user to the Home page.
I am not sure how to proceed.
Session have bad problems like timeout and refresh not available, do authentication using forms authentication you can choose this custom authentication sample
Or Else use cookies
HttpCookie MyCookie = new HttpCookie("MyCookie");
// for remveing if already Exists adding new;
Request.Cookies.Remove("MyCookie");
if (Request.Cookies["MyCookie"] == null)
{
MyCookie["id"] = id.ToString();
Response.Cookies.Add(MyCookie);
}
else
{
MyCookie["id"] = id.ToString();
// Request.Cookies.Remove("MyCookie");
Response.Cookies.Set(MyCookie);
}
// retries
int id = Convert.ToInt32(Request.Cookies["MyCookie"]["id"]);
Thanks for your responses.
"Session cannot be renewed" once it has expired.
Instead of renewing the session, create a new session in the ActionFilters Attribute (SessionTimeout).
The solution for my problem is to create a new session and re-link it with the domain object/user so that the user can continue his journey. I have done this in my SessionTimeout ActionFilterAttribute, to create new session for only a particular request which has the particular controller/action.
I have sessions recording a user's log in information but it gets lost due to my application ending.
Running my code from local host i have no issues, but now that i have lunched the site live i lose the session very quickly with in minutes.
I decided to log the Golbal.asax file and record when a session is started and ended and when my application starts and ends and if there are any application errors.
When a user navigates thought the website the session is checked if its null, if the session is not null i register hidden fields for that page to use my session values, but if the sessions are null i abandon them and redirect to my login page.
Here is what my log has shown me:
[11:52:25] Application has started
[11:52:25] Session has started
[11:52:35] Use session
[11:52:45] Use session
[11:52:54] Use session
[11:52:59] Use session
[11:53:5 ] Use session
[11:53:10] Use session
[11:53:15] Use session
[11:53:18] Session has ended
[11:53:18] Application has ended
[11:53:22] Application has started
[11:53:23] Session has started
[11:53:23] Abandon Session
[11:53:23] Session has ended
[11:53:23] Session has started
I navigated around my site with 7 clicks on the same hyper link basically just refreshing the page i was on, but for an unknown reason the session was lost and application was ended. As you can see from the log, this was all within a minute.
When a navigation link is clicked this is the code to check the session.
protected override void OnInit(EventArgs e)
{
LogClass Log = new LogClass();
if (this.Session != null && this.Session.Count > 0)
{
Log.Logger("Use session");
string email = (string)this.Session["Email"];
int practiceId = (int)this.Session["PracticeId"];
int practitionerId = (int)this.Session["PractitionerId"];
this.ClientScript.RegisterHiddenField("loggedInUserName", email);
this.ClientScript.RegisterHiddenField("practiceId", practiceId.ToString());
this.ClientScript.RegisterHiddenField("practitionerId", practitionerId.ToString());
}
else
{
Log.Logger("Abandon Session");
this.Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
Response.Redirect("~/Default.aspx");
}
base.OnInit(e);
}
What could be causing my session to get lost so quickly, and why is the just a problem when hosted live and not a problem from local host?
What causes the application to end, since i have no application errors logged?
In my asp.net application, i want to clear the session whenever my browser closed or my tab (if my browser containing multiple tabs)closed.
Please guide me to get out of this issue...
Short version, No.
There's no solid way of a server detecting if the client has closed their browser. It's just the nature of web development's asynchronous pattern.
Long version, if it's really, really important to you;
Put a bit of javascript in the page that sends a regular post to your website in the background and set up a serverside agent or service that disposes of the sessions if it doesnt receive these regular "heartbeat" signals.
You can put a javascript postback onto the page's unload() event but dont rely on it, it doesnt always fire.
This happens by default whenever you close your browser, and that's not just for ASP.NET. It's for most server-side programming languages that have a session state. Basically, any cookie that is added that doesn't specify an expiration date, will be deleted when the browser is closed.
Where this doesn't apply, is when you close a tab, which is something you will not have any control over because the tab close event will not get sent back to the Web server.
You can try to do that with javascript. Check it at:
http://www.codeproject.com/Tips/154801/How-to-end-user-session-when-browser-closed
Alternatively you can check you previous session state on every new browser opening and can Session.clear() or Session.abandon() the previous session.
this will make sure that every time you start application you will get new session.
use BasePage in your .net application.
Check the session.sessionid on basepage load.
More Inforamtion how to detect new session in basepage. BasePage.Session.Link
Hope this helps
regards
Shaz
public class BasePage : Page
{
protected string mySessionId;
private CurrentUser _currentUser;
public CurrentUser _CurrentUser
{
get { return ((CurrentUser)HttpContext.Current.Session["myCurrentUser"]); }
set { _currentUser = value; }
}
protected override void OnLoad(EventArgs e)
{
if (Session["myCurrentUser"] != null)
{
if (_CurrentUser.ProUser)
{
mySessionId = Session.SessionID; // it means New Session
}
if (!mySessionId.IsNullOrDefault() && mySessionId != Session.SessionID)
{
Session.Abandon(); //Abandon current session and start new one
}
}
}
}
I think cookies can better meet your requirement here for session management.
it means that session data should not be stored on the server and
should be with your call, so that you don't have to worry about
clearing the data on server.
Yes.First of all Browser automatically clear session when browser is closed. you can try to capture browser close or tab close event in browser using javascript function like on before unload and on unload. Mostly onbefore unload event captures browser close event in chrome, Firefox, IE 11.
You can use Session_End event of Global.aspx
//For Specific Session
Session.Remove("SessionName");
//All the Session
Session.Abandon();
In a module I wrote I store in the session the items the user added to his cart.
How would you handle this situation: The user adds a new item to his cart after the session timedout?
I can redirect to the homepage but then I'm causing the redirect to happen even when the session wasn't in use. like when the user isn't logged in, or his cart was empty.
How do you handle session timeout in your applications?
In this case, I might not use the built in ASP.NET Session provider. Instead you could set a persistent cookie for the customer's shopping cart session with an encrypted ID that maps to a session stored in the database, which stores the contents of the cart.
This way, you don't need to worry about timeouts, the session will continue for the lifetime of the cookie.
(If you really need to use ASP.NET Session, maybe you've already got code that uses it, then you could set the timeout to a very large number and configure the Session state provider to use SQL Server.)
Your page can have a javascript timer running and when the time runs out the page is redirected to another page, say login, with query string parameters as flags. When the Login screen is called with x flag, then the shopping cart is saved to the database for safe keeping. The key is to have the timeout be shorter than the session timeout.
ADDED:
Javascript on each page:
<body onload="PageLoad();">
<script type="text/javascript">
function PageLoad()
{
var t = setTimeout("ExceuteTimeOutTransfer()", 15000);
}
function ExceuteTimeOutTransfer()
{
window.location.href = "http://localhost/webplaying/Login.aspx?timeout=Y";
}
</script>
Code Behind on Login Page:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["timeout"] != null)
{
if (Request.QueryString["timeout"].ToUpper() == "Y")
{
SaveCart();
}
}
}
private void SaveCart()
{
lblResult.Text = "Cart Saved";
}
An alternative would be to store the cart in a cookie.
aware that there are a lot of questions relating to Forms Authentication and the persistence of cookies, but having spent most of a day delving around, I'm still having difficulties.
My Problem
I am working on a web app (VS2010 but webapp is f/w 3.5) which restricts access to certain parts of the app to authenticated users (whereas other parts are open). My problem is that my authentication cookies do not appear to be persisting after I close the browser.
My Approach
I have written a simple login.aspx page which is configured in web.config as follows:
<authentication mode="Forms">
...and the individual pages' behaviour are declared like so:
<location path="ClientManageAccount.aspx">
<system.web>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</location>
...which works fine in every respect EXCEPT for these cookie shenanigans...
I create the authentication cookie manually once I have authenticated my user's login & password against the database (which works fine) in the login.aspx page. If the user selects the 'keep me logged in' checkbox, the cookie is generated using this method:
private void GenerateAuthenticationCookie(int expiryInMinutes, Guid userGuid)
{
DateTime cookieExpiration = DateTime.Now.AddMinutes(expiryInMinutes); // change to months for production
var authenticationTicket =
new FormsAuthenticationTicket(
2,
userGuid.ToString(),
DateTime.Now,
cookieExpiration,
true,
string.Empty,
FormsAuthentication.FormsCookiePath);
// ticket must be encrypted
string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);
// create cookie to contain encrypted auth ticket
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authCookie.Expires = authenticationTicket.Expiration;
authCookie.Path = FormsAuthentication.FormsCookiePath;
// clear out existing cookie for good measure (probably overkill) then add
HttpContext.Current.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
HttpContext.Current.Response.Cookies.Add(authCookie);
}
The objective here is that I store a user Guid in the auth cookie, which I will then use to restore a user object into session (this is also in the login.aspx page, and my thinking is that I'd like to pluck the user guid from the auth cookie that I have created, and use it to stuff the corresponding user record into session and redirect to the requested page):
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
TryAutoLogin();
}
}
private void TryAutoLogin()
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null)
{
if (ticket.Name.Length > 0)
{
try
{
Guid userGuid = new Guid(ticket.Name);
KUser user = UserFunctions.GetUserFromUserGuid(userGuid);
if (user != null) Session["User"] = user;
FormsAuthentication.RedirectFromLoginPage(userGuid.ToString(), true);
}
catch (Exception anyException)
{
// don't do anything for now - do something smart later :-) }
}
}
}
}
Finally, here is the code for the login button on my login.aspx page:
protected void Submit_OnClick(object sender, EventArgs e)
{
long userId = 0;
UserAuthenticationStatus status;
status = (UserAuthenticationStatus)UserFunctions.UserAuthenticates(EmailAddress.Text, Password.Text, ref userId);
switch (status)
{
case UserAuthenticationStatus.Authenticated:
//email address and password match, account ok, so log this user in
KUser user = UserFunctions.GetUser(userId);
Session["User"] = user;
if (ChkRememberMe.Checked)
{
GenerateAuthenticationCookie(15, user.UserGuid); // 15 minutes
FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), true);
}
else
{
FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), false);
}
break;
case UserAuthenticationStatus.AuthButLocked:
// email/pwd match but account is locked so do something
ShowLockedAccountMessage();
break;
case UserAuthenticationStatus.EmailFoundIncorrectPassword:
case UserAuthenticationStatus.EmailNotFound:
case UserAuthenticationStatus.Unknown:
// either the email wasn't found, or the password was incorrect or there was some other problem
// present message stating this and offer chance to register
ShowFailedLoginMessage();
break;
default:
ShowUnavailableMessage();
break;
}
}
As you can see, there's nothing particularly complex going on, but despite the fact that the authCookie which is created in GenerateAuthenticationCookie(..) being created correctly (as far as I can tell) it does not persist.
One thing I have noticed is that if I place some code into the Application_AuthenticateRequest method in global.asax.cs, such as:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
if (cookie != null)
{
int x = 4; // just a dummy line so that I can set a breakpoint
}
}
...that breakpoint is sometimes hit following a new browser session, although it stops being hit once I navigate away from the startup page (in this case a dummy start.aspx page used purely for dev & testing).
So, apologies for the long question, but I'm truly suffering here.
Things I have checked/tried
Ensuring that the code is being executed - YES
Browser settings - i.e. no deletion of cookies on exit - CONFIRMED NO DELETION
Trying different timeouts - e.g. equal or different to the web.config timeout, doesn't seem to matter...
...and of course at least twenty or thirty different previous questions, but to no avail.
System/Dev Environment
Windows 7 64-bit, VS2010 (but proj is a 3.5), SQL Server 2008 Express.
On my dev server, this problem remains so I'm not sure it's necessarily environmental - that machine is a WS2008R2 box running SQL 2008R2 - and the same problem remains.
Does anyone, anywhere, have any ideas for things I can try here? I have a hunch I could get this working by intercepting the initial Application_AuthenticateRequest hit in global.asax.cs and stuffing something into session state to mark as 'authenticated' (to avoid an expensive authentication attempt every time that method is called, which turns out to be several times per page.
Thanks in advance,
John
OK, having spent all that time writing that, I had a moment of clarity and realised that (a) I didn't need to be doing any of that checking on the Page_Load() as (if this were working properly) the login.aspx page wouldn't be called at all, and (b) I ought to have been able to get to the cookie from the Session_Start - which is where I relocated the TryAutoLogin code.
This in itself was a step forward, but despite retrieving the cookie and therefore the user guid from it, I found that by I was still getting punted back to the login.aspx page.
It was at this point I recalled the fact that I have a parent master page and two child master pages - one which I set for non-authentication pages (e.g. homepage) and one for those pages requiring authentication. I vaguely recalled a problem with session timeouts and had placed the following code in the OnInit override:
if (Session["User"] == null)
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
Response.End();
}
...which in itself wasn't so bad (and avoided a nasty bug on timeouts) but also on the start.aspx page, I found this gem:
Session.Clear();
...in the Page_Load!
So, what was happening was that I was inadvertently clearing the session into which I had placed my newly recovered user record. Which meant that the authorisation master page's OnInit override was then detecting the absence of the user object and - ta dah! - signing the user out, which in turn removes the authorisation cookie...
So, a bit of wiring and some sleuthing later, and I can put this one to bed.
Thanks for reading (even if I did figure it out on my own)... :)