session timeout in asp.net mvc when refresh - c#

I am running an ASP.NET 4.0 application and published it using plesk control panel.I have done the following.
1.i set session timeout in web.config file as:
<sessionState timeout="20000"/>
I handled session variable in login controller like this:
Session["userId"] = lUser.userId;
Session["role"] = lUser.userType;
into other controller, the code is like below:
if (Session["role"] == null)
{
return RedirectToAction("Index", "Login");
}
else if (Session["role"].ToString() == "Admin" || Session["role"].ToString() == "Super Admin")
{
return View();
}
this code is ok in my local server but when published into real server using plesk control panel, it also ok for first time. but when i click the same menu second time it redirects to login page.

Try adding:
protected void Session_Start(Object sender, EventArgs e)
{
Session["init"] = 0;
}
to global.asax

Instead of SessionState mode="InProc" use SessionState Mode="StateServer", but you'll need to make sure the server where you're hsoting the application has the StateServer active.
<sessionState mode="StateServer" timeout="20000" cookieless="false" />

Related

Log out and redirect user to login screen ASP NET MVC / C #

I'm looking for a way to end my session and redirect the user to the login screen when my system gives TimeOut.
I tried to use Session.Abandon () according to some examples that I researched. But I do not know what I'm doing wrong. below is my code to do in Global.asax:
protected void Application_EndRequest(object sender, EventArgs e)
{
var context = new HttpContextWrapper(Context);
if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest())
{
var redirectLocation = context.Response.RedirectLocation.ToString();
context.Response.RedirectLocation = null;
context.Response.ContentType = "text/plain";
context.Response.Write("session_timeout;" + redirectLocation);
Session.Abandon();
Response.Redirect("~/Account/Login");
}
}
The code runs only until: context.Session.Abandon (); and does not redirect to the login screen unless I refresh the page.
public ActionResult LogOff()
{
HttpContext.Session.Remove(SessionKeys.UserType);//This will remove all keys from session variable. For example, if your session contains id, name, phone number, email etc.
HttpContext.Session.RemoveAll();//This will remove all session from application
FormsAuthentication.SignOut();
return RedirectToAction("Login", "Account");
}
I was able to resolve my question this way:
1 - I set a timeout time in my Web.config by adding this tag:
<sessionState timeout="16"></sessionState>
2 - I created a function in javascript that veridifca if the timeout time came to an end:
var sessionTimeoutWarning = #Session.Timeout- 1;
var sTimeout = parseInt(sessionTimeoutWarning) * 60 * 1000;
setTimeout('SessionEnd()', sTimeout);
function SessionEnd() {
alert("Your session has expired");
window.location = "/Account/SessionTimeOutLogOff";
}
Note: This function was put in my _Layout.chshtml

asp.net custom user authentication with master page

I am working on a small Inventory management system. I have almost created it on my local machine. It works as it is designed. I just moved it to my hosting account and now I am facing some problems.
1, After login, when user goes to different pages, open and closes forms, after some time it redirects to login page. I don't know why. Seems like some sort of exception was occurred or the session had gone empty. How to handle this condition?
2, Is this the right way to keep a check on the user login using a check in Page_Load event of master page?
My site uses a master page that has separate layout for top navigation menu and bottom body area. When the first time user lands on the site it login into the system and upon successful login I store his information in session. I am heavily using Session in all pages for ADD, DELETE, UPDATE purposes. When an add record is performed, I pass success of failure message in session to show after post back. Code behind of login page is given below:
protected void loginForm_OnAuthenticate(object sender, AuthenticateEventArgs e)
{
string error = "";
sMethodName = "loginForm_OnAuthenticate";
_objLoginBLL = new LoginBLL();
int iRetVal = _objLoginBLL.ValidateUser(loginForm.UserName, loginForm.Password, ref error);
if (iRetVal >= 0)
{
Session.Clear(); //Remove all stored Session variables.
Session[Constant.Session.LOGGED_IN_DATETIME] = DateTime.Now.ToString("yyyyMMddHHmmssfff");
Session[Constant.Session.LOGIN_USERNAME] = loginForm.UserName;
Session[Constant.Session.LOGIN_USER_ID] = iRetVal;
Session[Constant.Session.LOGIN_COMPANY] = ddlCompanies.SelectedValue;
Session[Constant.Session.LOGIN_FISCAL_YEAR] = ddlFiscalYear.SelectedValue;
Session[Constant.Session.IS_DIRECT_ACCESS] = "NO";
FormsAuthentication.RedirectFromLoginPage(loginForm.UserName, loginForm.RememberMeSet);
}
else
{
Logger.Log("User validation failed.", sClassName, sMethodName, DEBUG);
switch (iRetVal)
{
case -1:
loginForm.FailureText = Constant.Messages.INCORRECT_USER_OR_PASSWORD;
loginForm.Focus();
break;
case -2:
loginForm.FailureText = Constant.Messages.ACCOUNT_LOCKED;
loginForm.Focus();
break;
//case -3:
//TODO: Account doesn't exists
default:
var randToken = new Random().Next(1000);
Session[Constant.Session.TOKEN] = randToken;
var myHashtable = new Hashtable
{
{Constant.Session.TOKEN, randToken},
{Constant.Fields.ERROR_KEY, iRetVal}
};
Response.Redirect(WebFunctions.CreateQueryString(Constant.Urls.Error, myHashtable));
break;
}
}
}
I am continuously checking if the session doesn't contain any user id then redirect it to the login page. The code behind of my master page is given below:
protected void Page_Load(object sender, EventArgs e)
{
if (Session[Constant.Session.LOGIN_USER_ID] == null)
{
FormsAuthentication.RedirectToLoginPage();
return;
}
CheckDBConnection();
Initialize();
}
Any help or tips will be appreciated.
You can view the site here: www.paracha.net (I can share guest account credentials in private message if anyone is interested)
First of all, keep in mind that the session cookie is not encrypted, so you should not be using the session to store any confidential information.
Secondly, you should not be checking the authentication on every Page_Load. Instead, you should configure the page access in web.config:
<configuration>
<system.web>
<authorization>
<deny users="?"/>
</authorization>
</system.web>
</configuration>
This will protect all your pages so only authenticated (i.e. logged in) users will see the page, while all others will be redirected to the login page.
If you have some pages (e.g. a splash page) or folders (e.g. the images folder) that you want them to be accessible to all users, then add a section for each page or folder:
<configuration>
<location path="splash.aspx">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="images">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
</configuration>
In order for this to work, you should be using forms authentication. Here are the settings in web.config:
<configuration>
<system.web>
<authentication mode="Forms">
<forms
name=".YOURNAME_AUTH"
loginUrl="login"
defaultUrl="/"
protection="All"
timeout="30"
path="/"
requireSSL="true"
slidingExpiration="true"
cookieless="UseCookies"
domain=""
enableCrossAppRedirects="false">
</forms>
</authentication>
</system.web>
</configuration>
Obviously, you will need a login.aspx page, and when you click the Log in button, you need to authenticate the user like this:
protected void btnLogIn_Click(object sender, EventArgs e) {
string Username = txtUsername.Text;
string Password = txtPassword.Text;
try {
if (ValidateUser(Username, Password)) {
FormsAuthentication.RedirectFromLoginPage(Username, false);
}
else {
lblMessage.Text = "Incorrect Credentials.";
lblMessage.ForeColor = Color.Red;
}
}
catch {
lblMessage.Text = "Login Failed.";
lblMessage.ForeColor = Color.Red;
}
}
The function ValidateUser() can do anything you want for authentication. You can validate the credentials against your database if you like.
If you use FormsAuthentication, you do not need to check Session[Constant.Session.LOGIN_USER_ID] manually. It will redirect to Login page automatically for which you can configure in web.config.
Another thought
It is not directly related to your question. It is just an alternative approach.
Instead of creating multiple session states, you can create custom Context to keep track of the current logged-in user's information
E.g. You can store Company and Fiscal Year properties inside MyUser class.
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.User != null &&
HttpContext.Current.User.Identity.IsAuthenticated)
{
MyContext.Current.MyUser =
YOUR_BLL.GetUserByUsername(HttpContext.Current.User.Identity.Name);
}
}
public class MyContext
{
private MyUser _myUser;
public static MyContext Current
{
get
{
if (HttpContext.Current.Items["MyContext"] == null)
{
MyContext context = new MyContext();
HttpContext.Current.Items.Add("MyContext", context);
return context;
}
return (MyContext) HttpContext.Current.Items["MyContext"];
}
}
public MyUser MyUser
{
get { return _myUser; }
set { _myUser = value; }
}
}
}
Addition
C# is strongly type language, so you should not encode the variable name with type of variable. E.g. objLoginBLL and iRetVal. Please read C# Design Guideline or Essential C# 6.0 (Page 7).

Redirect to different pages for request coming from subdomain site

I have main site and its subdomain site.
When user is entering main site url www.mysite.com it should get redirected to 'Login.aspx'
When user is entering sub domain site url sample.mysite.com it should get redirected to 'Welcom.aspx'
To achieve this what is the best way to do ?
Changes in IIS settings ?
Modify Code in Global.asax
Create Dummy Page for redirection
What code i have to wrote if i required to modify global.asax ?
Personally I will choose 2nd option, modify the Global.asax file.
void Application_BeginRequest(Object source, EventArgs e)
{
string host = HttpContext.Current.Request.Url.Host.ToLower();
if (host == "www.mysite.com")
{
//Incase if you are using any session
if (Session["User"] == null)
Response.Redirect("Login.aspx");
else
{
//validate the session
Response.Redirect("Home.aspx");
}
}
else if (host == "sample.mysite.com")
{
Response.Redirect("Welcome.aspx");
}
}
To achieve the redirection , modify the code in global.asax will be the best one

Check authentication ticket expiration without affecting it

I am trying to implement a Web Application Project where my web pages can check the server for the Authentication ticket expiration date/time using AJAX.
I am using Forms Authentication with slidingExpiration.
The problem I run across is I can't figure out how to check the value without resetting it. I created a simple page - CheckExpiration.aspx - below is the code behind:
private class AjaxResponse
{
public bool success;
public string message;
public string expirationDateTime;
public string secondsRemaining;
public string issueDate;
}
protected void Page_Load(object sender, EventArgs e)
{
AjaxResponse ar = new AjaxResponse();
JavaScriptSerializer js = new JavaScriptSerializer();
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
string expiration = id.Ticket.Expiration.ToString();
TimeSpan timeRemaining = id.Ticket.Expiration - DateTime.Now;
ar.success = true;
ar.expirationDateTime = expiration;
ar.issueDate = id.Ticket.IssueDate.ToString();
ar.secondsRemaining = timeRemaining.Minutes.ToString() + ":" + timeRemaining.Seconds.ToString();
}
else
{
ar.success = false;
ar.message = "User not authenticated";
}
string output = js.Serialize(ar);
Response.Write(js.Serialize(ar));
}
I call this page from the Master page in my application using ajax every second. Past the halfway point in the authentication expiration, the expiration gets reset.
How do I prevent this behavior? Is there anything I can do in the header of the request maybe?
Why don't you store the expiration as a session variable that you compute yourself? You only need to get the value of id.Ticket.Expiration once. Then each call, get the value from the server and increment it accordingly, and store it back on the server.
http://msdn.microsoft.com/en-us/library/ms178581%28v=vs.85%29.aspx
Pseudocode:
if(!Session.KeyExists("Expiration"))
{
Session["Expiration"] = id.Ticket.Expiration;
}
Session["TimeRemaining"] = Session["Expiration"] - DateTime.Now;
// get all ajaxy here
Put your CheckExpiration.aspx page in its own application and deploy this as a virtual directory beneath your main application. In that virtual directory, configure slidingExpiration=false. Your code will work as-is but will not regenerate the ticket when it gets below half the time until expiration.
Here's what I did in a quick local project to verify that it works:
Created a new web application AuthTest4 and configured it to use local IIS server in path /AuthTest4
Went into IIS and changed the Machine Key setting for /AuthTest4 to uncheck all the AutoGenerate/Isolate options and generated its own MachineKey.
Created an empty web application ExpCheck and put your CheckExpiration.aspx code in it
Configured ExpCheck web application to use local IIS in the virtual directory /AuthTest4/ExpCheck
Modified the web.config of ExpCheck application to have only the section shown below
ExpCheck web.config. All other security settings will cascade down from the parent virtual directory.
<system.web>
<authentication mode="Forms">
<forms slidingExpiration="false" />
</authentication>
</system.web>

ASP.NET MVC Session.IsNewSession issue with Google Chrome

I'm currently working on a Session expired piece of logic for my ASP.NET 3.5 MVC 2 project to log out a user and redirect them to the AccountController LogOn action.
I have the following attribute on all my actions that care about session state, and this piece of code works in IE 8, but not Firefox 4 or Google Chrome 10. The symptom is when I attempt to navigate to a view represented by an action with my [SessionExpireFilter] attribute, the ctx.Session.IsNewSession property in the below code is evaluating as "true" every time, even if I'm only seconds into my 30-minute session.
public class SessionExpireFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
HttpContext ctx = HttpContext.Current;
// check if session is supported
if (ctx.Session != null && ctx.Session.IsNewSession)
{
// If it says it is a new session, but an existing cookie exists, then it must
// have timed out
string sessionCookie = ctx.Request.Headers["Cookie"];
if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") >= 0))
{
FormsAuthentication.SignOut();
ctx.Response.Redirect("~/Account/LogOn");
}
}
base.OnActionExecuting(filterContext);
}
}
Is there any way to figure out why Chrome and Firefox are behaving this way, but IE is not? Thanks in advance.
EDIT: This is not working in FF as I originally believed. I am being directed to my LogOn action immediately after logging in and attempting to access an action with my SessionExpireFilter attribute.
ASP.NET will create a new session for every request unless you store something in it.
Try adding the code below to your Global.asax. It works in my MVC2 and MVC3 apps with the same SessionExpireFilterAttribute.
protected void Session_Start()
{
Session["Dummy"] = 1;
}
We can add session_start method in Golbal.asax file in MVC appliaction.
protected void Session_Start(object sender, EventArgs e)
{
HttpContext.Current.Session.Add("UserId" , null);
}
Then when application starting your session will be created. and then session will be not isNewSession 'True', otherwise it will be always 'True'

Categories

Resources