We employ Out-of-Process SQL Session State, ASP.NET 3.5 MVC 1.0 and Forms Authentication using IIS 7.
A user's session is correctly set on logon and will time out as expected, redirecting them to a special "Time out" login page. The problem is that some (not all) users log in and are (from what I can tell) immediately unauthenticated and are required to log back in (i.e. redirected to the original "Login" page).
Might anyone have an idea why our users are intermittently being kicked out?
EDIT: I've since added logging on every Application_AuthenticateRequest event, I can tell you that before the user is booted out both the Auth ticket is authenticated, persistent and expires two days later and the request is also authenticated. Upon arriving at the logon page the user is no longer authenticated.
EDIT #2: We've made some progress, it would appear as though users may be unauthenticated because this web app is looking for scripts and other content in the parent app for which users are not authenticated. The original format for inclusion of these scripts is as follows:
<script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script>
I have corrected it to:
<script src="<%= Url.Content("~/Scripts/MicrosoftAjax.js") %>" type="text/javascript"></script>
ANSWER The above changes to our script references in our .master pages resolved the issue. It explicitly tells the app to look in the root folder of the current app. Thank you to all who helped. I wish I could have marked more than one as the answer!
Below is our login Action:
[AcceptVerbs(HttpVerbs.Post)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameter type as Controller.Redirect()")]
public virtual ActionResult LogOn(string userName, string password, string returnUrl)
{
if ((HttpContext.Current.User == null) || (!HttpContext.User.Identity.IsAuthenticated))
{
if (!ValidateLogOn(userName, password))
{
try
{
return View();
}
catch (Exception ex)
{
throw new Exception(string.Format("User validation failed at LogOn: {0}", ex.ToString()));
}
}
}
bool rememberMe = true;
FormsAuth.SignIn(userName, rememberMe);
Session["userName"] = userName;
if (!String.IsNullOrEmpty(returnUrl))
{
try
{
return Redirect(returnUrl);
}
catch (Exception ex)
{
throw new Exception(string.Format("User redirect to returnUrl ({0}) failed: {1}", returnUrl, ex.ToString()));
}
}
else
{
try
{
return RedirectToAction("Index", "RodWebUI");
}
catch (Exception ex)
{
throw new Exception(string.Format("User redirect to action: Index, controller: RodWebUi failed: {0}", ex.ToString()));
}
}
}
Below is our timeoutlogon action:
public virtual ActionResult TimeOutLogon()
{
try
{
FormsAuth.SignOut();
ViewData["TimeoutMsg"] = "Session timed out. Please log back in.";
return View();
}
catch (Exception ex)
{
throw new Exception(string.Format("Error with redirecting to TimeOutLogon: {0}", ex.ToString()));
}
}
I've since added the following check to our global.asax to log the current status of the request and auth ticket. Everything is authenticated and OK prior to being kicked back to LogOn.
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity identity = (FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = identity.Ticket;
LogFunctionCall(HttpContext.Current.User.Identity.Name, "", "User Authentication Check", "",
string.Format("Auth ticket is expired: {0}, expiration date: {1}, is persistent: {2}, issued: {3}",
ticket.Expired, ticket.Expiration, ticket.IsPersistent, ticket.IssueDate), "", 0);
LogFunctionCall(HttpContext.Current.User.Identity.Name, "", "User Authentication Check Line #2", "",
string.Format("Raw URL: {0}, Request is authenticated: {1}", HttpContext.Current.Reque开发者_JS百科st.RawUrl, HttpContext.Current.Request.IsAuthenticated), "", 0);
}
}
}
}
Do you have a load balanced website?
If so, are the machineKeys the same on all nodes? Is the Forms Cookie name the same? If there are discrepancies in those values you can login on one node and seem unauthenticated to the other node.
ASP.Net redirects users to the login page if they are not authenticated OR if they are not authorized to view the resource they are trying to go to.
This might be silly but could the returnUrl be pointing to the login page?
How does the login page behave when the user is already logged in?
public partial class MasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void signout_Click(object sender, EventArgs e)
{
Response.Write("<script language=javascript>var wnd=window.open('','newWin','height=1,width=1,left=900,top=700,status=no,toolbar=no,menubar=no,scrollbars=no,maximize=false,resizable=1');</script>");
Response.Write("<script language=javascript>wnd.close();</script>");
Response.Write("<script language=javascript>window.open('login.aspx','_parent',replace=true);</script>");
Session["name"] = null;
}
}
I'm also adding on all page this code.
protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetAllowResponseInBrowserHistory(false);
}
}
Spidey sense says that the ASP.NET process or app pool is recycling on you. Could happen for a few reasons. Since sessions are out of process, they won't get eaten by this event.
I'd look at the event logs to see if anything hinkey is going on there.
精彩评论