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.
Related
I am having trouble invalidating .AspNetCore.Identity.Application cookie in ASP.NET Core Identity once the user log out.
Once user clicks on log out below code will execute.
public async Task<IActionResult> Logout(LogoutInputModel model)
{
// build a model so the logged out page knows what to display
LoggedOutViewModel loggedOutViewModel = await BuildLoggedOutViewModelAsync(model.LogoutId);
_logger.LogInformation($"loggedOutViewModel : {JsonConvert.SerializeObject(loggedOutViewModel)}");
if (User?.Identity.IsAuthenticated == true)
{
// delete local authentication cookie
await _norskTakstSignInManager.SignOutAsync();
//clear cookies
var appCookies = Request.Cookies.Keys;
foreach (var cookie in appCookies)
{
Response.Cookies.Delete(cookie);
}
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
// check if we need to trigger sign-out at an upstream identity provider
if (loggedOutViewModel.TriggerExternalSignout)
{
// build a return URL so the upstream provider will redirect back
// to us after the user has logged out. this allows us to then
// complete our single sign-out processing.
string url = Url.Action("Logout", new { logoutId = loggedOutViewModel.LogoutId });
// this triggers a redirect to the external provider for sign-out
return SignOut(new AuthenticationProperties { RedirectUri = url }, loggedOutViewModel.ExternalAuthenticationScheme);
}
return View("LoggedOut", loggedOutViewModel);
}
This successfully clears all the cookies in the browser, however, if I grab the value of the cookie named ".AspNetCore.Identity.Application" prior to signing out, then add it back in on to the browser, then i can log in to the application without entering user credentials.
I tested few flows setting up cookie expiration time in different ways but non of them seem to work correctly.
I want to know way to invalidate the cookie without just clearing to resolve this issue.Then user should not be able to enter cookie manually and log in to the system. Any help is hugly appreciated. Thank you.
That's by design... one thing you can do is try updating the user's security stamp after logout, using UserManager.UpdateSecurityStampAsync.
This way the cookie's security stamp won't match the one in the database and the cookie will no longer be valid (however, no other cookie issued to that user will, even if they haven't "signed out"... so if a user has several sessions opened, all of those cookies will stop being valid, not just the one you signed out).
Identity doesn't track specific user sessions (it just validates the cookie against the user, and if it matches, it matches). If you want to be able to selectively remove sessions, you'll have to track them yourself
For me the best security practice is save every login and logout in one record with an unique random ID as GUID, then save this "id session" into the claims, and check this everytime the user access, if the ID in the claim is correct to that session.
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.
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?
I have a facebook application which is session based. i am having bad behaviour as follows: if the user is using the app then logs out from facebook and some other user logs in to facebook and logs in the app they see the user data who just logged out.
Essentially I d like to clear the session every time visitor hits the first page.
I have a HomeController which extends BaseController in base controller i check if the user has a session.
where should i put Session.clear() in order to prevent user to access old user session?
on
HomeController{
[authorize for facebook]
indexAction{
redirect to home action
}
}
my concern is that when indexaction is invoked Before that base controller will be invoked and i will get a infinite loop.
Note: I m using a UserCookie which i store the user id and expiration of the cookie within.
any ideas?
It looks like you want to check if Facebook user ID matches data in session state. The easiest would be to put something like Session["FBID"]=facebookId and than check on every request if current facebookId matches `Session["FBID"], if not - clear session (irrespective of current location).
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
}
}