Forms Authentication and authentication cookie not persisting - c#

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)... :)

Related

How can I delete this cookie? ASP.NET MVC

I try to delete this cookie:
First of all a bit of background. This is a token for verification on different sites within the same domain. I make the central login page. This page is working fine, except the log out. Every other cookie, I want to delete, gets deleted by JQuery cookie $.removeCookie('cookieName'). And I know, I can't delete this from the JavaScript, because of the secure-flag.
So I tried deleting it from a controller method. I call this method via ajax from JavaScript.
$.ajax({ur:'/Login/ExpireToken'})
I can see that it works in the Chrome Console Network Tab.
public void ExpireToken()
{
Response.Cookies.Remove("crowd.token_key");
}
But this, I don't know why, makes a new cookie, with the same name, empty value, the whole domain of the login page and no flags set.
So I tested, if the backend can find the cookie I want.
public string ExpireToken()
{
return Response.Cookies["crowd.token_key"].Value;
}
It returns the correct value and doesn't create a new/false one.
After this I tried to set the expires field to one day in the past or to now. I don't know, why this should work, because the expiration date of this cookie is already in the past.
public void ExpireToken()
{
Response.Cookies["crowd.token_key"].Expires = DateTime.Now.AddDays(-1d);
}
And guess what, it doesn't work. It does literally nothing.
Other ways that don't work
if (Request.Cookies["crowd.token_key"] != null)
{
var c = new HttpCookie("crowd.token_key");
c.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(c);
}
As per the doc, you are doing things right in your las attemp, the one setting the expiration date to yesterday. Quote:
The technique is to create a new cookie with the same name as the
cookie to be deleted, but to set the cookie's expiration to a date
earlier than today. When the browser checks the cookie's expiration,
the browser will discard the now-outdated cookie
I would put a breakpoint and debug to check cookie names, if everything is fine, perhaps the web browser is missbehaving.
HttpCookie aCookie;
string cookieName;
int limit = Request.Cookies.Count;
for (int i=0; i<limit; i++)
{
cookieName = Request.Cookies[i].Name;
aCookie = new HttpCookie(cookieName);
aCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(aCookie);
}

Response.Redirect Fails But then Works on Refresh IIS Express VS2013

I have an ASP.NET project in Visual Studio 2013, running locally in IIExpress (Version 8.08418.0) for testing.
The main page (adminDefault.aspx) redirects user to Login.aspx to authenticate (which is done silently based on userID that was passed to adminDefault.aspx as a url variable). The login page sends it back to adminDefault.aspx upon successful authentication. Default then loads data into a Gridview.
The whole process takes about 15 seconds.
When I run this from Visual Studio 2013, I get an error "This page can't be displayed" in about 4 seconds. But if I manually hit refresh, after working for a bit, everything comes in fine.
In my code, suspecting a timeout, I implicitly set this long enough to run through everything:
if (!this.IsPostBack)
{
Session.Timeout = 120; // seconds before timeout
try
{
// OnUser should have been set from Login.asp. If it is null, send to Login
MembershipUser onUser = Membership.GetUser();
if (onUser == null)
{
Response.Redirect("/login.aspx", true);
}
else
{
String currentUserName = Membership.GetUser().UserName;
userRoles = Roles.GetRolesForUser(Membership.GetUser().UserName);
}
}
Even if the Session.Timeout is being ignored, the default is 20 Seconds, so I would expect it to work anyway.
So:
1) Why is the first run through failing?
2) Is there a way I can prevent it? Failing that can I catch the page not found, and refresh automatically?
EDIT: This has something to do with the trip to Login.aspx and back. If I remove Response.Redirect("/login.aspx", true);
Then this works as expected. The problem is, I need the Login.aspx for validation. Anyone have any thoughts as to why the trip to Login and back is not working... and then does upon refresh?
When I try to run this in Chrome, I don't get as far. Chrome shows me this:
Hitting the here just cycles for a moment and comes back to the screen.
The Developer Tool on IE are not helpful (at least that i can see) in this case. When I run my project in the debugger, it launches a new IE session. Before I can turn on developer tools and press "Play" to record events, the session has given me "Cannot display the page" error. Of course I can hit "play" in the tools and then refresh, but of course everything runs then without error. The refresh makes everything run right. I need to discover why it fails before then.
EDIT: This is the Login.aspx and Web.Security Code. I didn't write it, but it looks boilerplate:
protected void Page_Load(object sender, EventArgs e)
{
string userName = "";
bool authenticated = FormsAuthentication.Authenticate(ref userName);
if (authenticated)
{
FormsAuthentication.RedirectFromLoginPage(userName, false);
}
}
And the Authentication code looks like this:
/// <summary>
/// Validates a user based on the session id found in the ReturnURL against credentials stored in the ASP.NET membership.
/// </summary>
/// <param name="userName">The user name.</param>
/// <returns>true if the user name and password are valid; otherwise, false.</returns>
public static bool Authenticate(ref string userName)
{
bool Authenticated = Authenticate(ref userName, GetSessionId());
return Authenticated;
}
/// <summary>
/// Redirects an authenticated user back to the originally requested URL or the default URL using the specified cookie path for the forms-authentication cookie.
/// </summary>
/// <param name="userName">The authenticated user name. </param>
/// <param name="createPersistentCookie">true to create a durable cookie (one that is saved across browser sessions); otherwise, false. </param>
/// <param name="strCookiePath">The cookie path for the forms-authentication ticket. </param>
public static void RedirectFromLoginPage(string userName, bool createPersistentCookie, string strCookiePath)
{
System.Web.Security.FormsAuthentication.SetAuthCookie(userName, false, strCookiePath);
// Redirect back to request page.
HttpContext.Current.Response.Redirect(GetRedirectUrl());
}
I think in your initial if statment you are assuming everyone is either logged in or not logged in.But users that are not logged in and people who visit that can also be anonymous (?). What you want to do is secure this admin.Default page and only allow authorized users. Currently your 2 conditions are send back the user to the login.aspx page (that they are currently on) if a user = null or get a role.
Authentication is about knowing who the user is while authorization is all about access to resources .You want only authorized users to access that resource.
I would put the admin.Default.aspx,admin.Default.cs and admin.Default.designer.cs in their own folder called AdminSecure. Then after adding them inside that folder right click and add a Web.config file. In that Web.config what you need to do is deny anonymous users. So they automatically get redirected when they try and access that AdminDefault page.
//denies non logged in users ? == anonymous
<xml version="1.0"?>
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
//this can allow particular users
<allow users="User1#mail.com"/>
//deny everyone but one user:
<allow users="User1#mail.com"/>
<deny users="*"/>
comment out your current code hope this helps.
If Login.aspx redirects to adminDefault.aspx before it gets to persist a session to your browser, an infinite redirect loop will happen.
My clues:
1) As you already have a redirect loop - although not intentionally infinite - there is a risk of it becoming infinite under unhandled circumstances
2) you say that a timeout may be occurring, but the server side timeout is ignored: this leads me to think that this happens client side, and in fact could be your browser breaking the redirect loop as a safety measure
3) refreshing helps: this breaks the redirect loop after your session has been persisted client side
4) removing your redirection to adminDefault.aspx helps: this not only breaks the infinite loop, but removes the concept of the redirect loop
A few things you can to do test the redirect loop theory:
1) set a breakpoint on Session.Timeout = 120; and see where things go from there. You'll expect to get to Response.Redirect("/login.aspx", true); once only, but will probably see this line being hit continuously (once per redirection)
or
2) install Fiddler and monitor your redirections.
If the above theory is correct, you have to ensure that Login.aspx gets to persist a session to the browser before redirecting to adminDefault.aspx. I.e., try and remove the redirection to adminDefault.aspx and see if you have gotten a session cookie after redirecting to Login.aspx - if not, you have your suspect. In short, Login.aspx is not done with it's work before you redirect back to adminDefault.aspx - so you have to let it. I can't be more specific without the Login.aspx code.
Based on your application circumstance in the comments, you cannot manage the authentication/authorization via web.config. And, Membership class is usually accessed if you have your custom provider, it's not the default way of accessing logged in users. So do either one of those:
Check the logged in user in your if statement the following way:
if (User.Identity.IsAuthenticated)
{
Response.Redirect("/login.aspx", true);
}
else
{
String currentUserName = Use User.Identity.Name; // accessing the logged in uer
userRoles = Roles.GetRolesForUser(currentUserName); // not sure about this step, have you added your roles to web.Config? or from where you get them
}
Depends on how your ERP integrates with your app (you should be using a custom provider), check where the users get authenticated. (ex. who is calling Membership.ValidateUser(strUsername,strPassword) . And make sure your login.aspx page is updating the session state.
Check this page for more information about implementing a custom provider

Cookies and Sessions Expiration in .NET

I have an MVC4 single application page. In the log-in page there are 3 fields: user, password and "remember me" checkbox.
The C# login code is this:
if (WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
return Json(new { success = true, redirect = returnUrl });
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
I want to do this:
If a user logs in with "remember me" true - The cookie will stay until the user logs off.
If the user logs in with "remember me" false - The cookie will expire after 3 hours.
In web.config I have this code:
<authentication mode="Forms">
<forms loginUrl="~/" timeout="180" cookieless="UseCookies" slidingExpiration="false" />
</authentication>
<sessionState timeout="180" />
The problem is when the user doesn't touch the page for a short time (10-30 mins usually), and then the user tries to do something in the page - there is an error
"Authorization has been denied for this request."
(Although sessionStation is more than 30 minutes!)
After the user refresh the page - if the cookie hasn't expired yet - everything works fine. But of course I don't want to make the user refresh the page every 15 minutes or so, it's a single-page-application.
So, I tried to change slidingExpiration to "true" and create a ping (with ajax) every 17 minutes and it really stopped the session expiration and the annoying message - but the cookie didn't expired after 3 hours (I logged in with remember me 'false')!
What can I do?
Right click your application pool from IIS management console and look for "Idle time-out(minutes)".
You can adjust the setting to 0 (zero) which effectively disables the timeout so that the application pool will never shut down due to being idle.
I would double check your IIS settings. See what your App Pool Idle Timeout value is set to. By default it's 20 minutes. When the App Pool goes idle (no users accessing the app pool) for twenty minutes, you will loose session state (All data stored in the session will be cleared).
With more users this problem would work itself out, but presuming you are the only person testing, increasing this value to something greater than 180 minutes will prevent the timeout, or you could set the value to zero to disable the app pool idle timeout altogether.
See this answer for information on checking your app pool timeout in IIS Express... https://stackoverflow.com/a/10222419/386856
Do note that a dead app pool can take several seconds to re-spawn. It may be beneficial to increase this value anyways. This will prevent users from having an extremely slow experience if they happen to be the person that's unlucky enough to have to wait for the app pool to restart.
Update
To allow for a change in timeout for users who don't click remember me, you can create a custom attribute or you could modify the FormsAuthentication timeout via C#. Here are good references on setting the timeout via code. https://msdn.microsoft.com/en-us/library/system.web.configuration.formsauthenticationconfiguration.timeout%28v=vs.110%29.aspx and https://msdn.microsoft.com/en-us/library/system.web.configuration.formsauthenticationconfiguration(v=vs.110).aspx If you want the timeout to expire right at 3 hours, even if the user has activity be sure slidingExpiration is false in your web config. If you want the timeout to expire 3 hours after the user's last activity be sure slidingExpiration is true. So before you set the cookie try something like the following (Be sure to check the OpenWebConfiguration path):
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("/aspnetTest");
AuthenticationSection authenticationSection = (AuthenticationSection)configuration.GetSection("system.web/authentication");
FormsAuthenticationConfiguration formsAuthentication = authenticationSection.Forms;
formsAuthentication.Timeout = System.TimeSpan.FromHours(3);
formsAuthentication.SlidingExpiration = true;
I solved this by just creating my own encrypted cookie which will persist the user's session if present. In an action filter attribute, check if the user's session is expired, check for this cookie. If the cookie exists, verify the information and reestablish the session. If the user doesn't have a session, doesn't have a cookie, or the encrypted credentials are incorrect, redirect the user to the login page. Since everything is handled in the code, there is no guess work on the server settings.
On login with remember me checked:
if (RememberMe ?? false)
{
var authCookie = new HttpCookie(Config.AuthorizationCookie);
authCookie.Values.Add("ID", Crypto.EncryptStringAES(UserSession.Current.Account.ID.ToString(), Config.SharedSecret));
authCookie.Expires = DateTime.Now.AddDays(30);
AuthorizationCookie = authCookie;
}
Response.AppendCookie(AuthorizationCookie);
On page visit without session (done inside an attribute attached to necessary controllers and actions):
_account = UserSession.Current.Account;
// check if there is currently an account in the session
if(_account == null)
{
// check the user authorization cookie for a user id
HttpCookie authCookie = HttpContext.Current.Request.Cookies[Config.AuthorizationCookie] ?? new HttpCookie(Config.AuthorizationCookie);
if (authCookie.HasKeys && !String.IsNullOrEmpty(authCookie["ID"]))
{
// decrypt the user id for database lookup
_userID = Crypto.DecryptStringAES(authCookie.Values["ID"], Config.SharedSecret);
}
}
Re-establish the session if necessary (done inside a database connection)
// called within a database connection's using statement
protected override void Query(DatabaseContext db)
{
// check the database for the user account
if(_account == null && !String.IsNullOrEmpty(_userID))
{
int tempID;
int? id;
id = int.TryParse(_userID, out tempID) ? tempID : (int?)null;
if(id.HasValue)
{
_sessionRestored = true;
_account = db.User.Find(id);
if(_account != null)
{
_account.LastLogon = DateTime.UtcNow;
db.SaveChanges();
}
}
}
}
Finally restore the session:
if (_account != null)
{
// set the current account
UserSession.Current.Account = _account;
if(_sessionRestored)
{
UserSession.Current.Refresh();
}
}
Your code may look a bit different but that is the crux of how I did it.

Redirecting to another page on Session_end event

I would like to auto-redirect to login page when session time outs.
In web.config file, i have the following code
<configuration>
<system.web>
<sessionState mode="InProc" timeout="1"/>
</system.web>
</configuration>
In Global.asax file-
protected void Session_End(object sender, EventArgs e)
{
Response.Redirect("LoginPage.aspx");
}
But after time-out, i am receiving the following error:
HttpException was unhandled by user code.
Response is not available in this context.
Any clue to solve this issue?
Session_End is called when the session ends - normally 20 minutes after the last request (for example if browser is inactive or closed).
Since there is no request there is also no response.
I would recommend to do redirection in Application_AcquireRequestState if there is no active session. Remember to avoid loops by checking current url.
Edit: I'm no fan of .Nets built in authentication, Example goes in Global.asax:
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
try
{
string lcReqPath = Request.Path.ToLower();
// Session is not stable in AcquireRequestState - Use Current.Session instead.
System.Web.SessionState.HttpSessionState curSession = HttpContext.Current.Session;
// If we do not have a OK Logon (remember Session["LogonOK"] = null; on logout, and set to true on logon.)
// and we are not already on loginpage, redirect.
// note: on missing pages curSession is null, Test this without 'curSession == null || ' and catch exception.
if (lcReqPath != "/loginpage.aspx" &&
(curSession == null || curSession["LogonOK"] == null))
{
// Redirect nicely
Context.Server.ClearError();
Context.Response.AddHeader("Location", "/LoginPage.aspx");
Context.Response.TrySkipIisCustomErrors = true;
Context.Response.StatusCode = (int) System.Net.HttpStatusCode.Redirect;
// End now end the current request so we dont leak.
Context.Response.Output.Close();
Context.Response.End();
return;
}
}
catch (Exception)
{
// todo: handle exceptions nicely!
}
}
If you are using something like FormsAuthentication for maintaining the security of your application, then this part (that part that you are trying to do) will be done for you. If FormsAuthentication discovers that a user's session has expired it will redirect him or her back to you login page.
Second, don't rely too much on Session_End because it will never trigger if you change session provider from InProc to SQLServer or other out of process provider.
You can use session property IsNewSession to detect whether it is session timeout or not.
The ASP.NET HttpSessionState class has IsNewSession() method that returns true if a new session was created for this request. The key to detecting a session timeout is to also look for the ASP.NET_SessionId cookie in the request.
Definitely I too agree that we should put the below code in some so called a custom BasePage, which is used by all pages, to implement this effectively.
override protected void OnInit(EventArgs e)
{
base.OnInit(e);
if (Context.Session != null)
{
if (Session.IsNewSession)
{
string CookieHeader = Request.Headers["Cookie"];
if((CookieHeader!=null) && (CookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
{
// redirect to any page you need to
Response.Redirect("sessionTimeout.aspx");
}
}
}
}
check this link for more explanations if you want to put the above code in a base page class .
You should use Application_AcquireRequestState
You'll find that Application_AuthenticateRequest no longer has a session context (or never had one).
In my research into this I cam across this post which solved it for me.
Thanks go to Waqas Raja.
asp.net: where to put code to redirect users without a session to the homepage?
I think you are getting "Response is not available in this context" because the user is not making a request to the server, and therefor you cannot provide it with a response. Try Server.Transfer instead.
The easiest way what I feel is to use Meta information and get the trick working. Consider we have a page WebPage.aspx add the below code in the the WebPage.aspx.cs file.
private void Page_Load(object sender, System.EventArgs e){
Response.AddHeader("Refresh",Convert.ToString((Session.Timeout * 60) + 5));
if(Session[“IsUserValid”].ToString()==””)
Server.Transfer(“Relogin.aspx”);
}
In the above code, The WebPage.aspx is refreshed after 5 seconds once the Session is expired. And in the page load the session is validated, as the session is no more valid. The page is redirected to the Re-Login page. Every post-back to the server will refresh the session and the same will be updated in the Meta information of the WebPage.aspx.
you can simply do the following in web.config
<configuration>
<system.web>
<sessionState mode="InProc" timeout="1" loginurl="destinationurl"/>
</system.web>
</configuration>
Since, we can't redirect from Session_End as no response/redirect is present there.By using this you will be redirected to destinationurl when session will timeout.Hope this helps.

How can I handle forms authentication timeout exceptions in ASP.NET?

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
}
}

Categories