A data-collection site using MVC3 with jQuery and Ajax. The site is using tabs (jquery ui tabs), loaded as partials and each connected to ajax-forms. So each tab is loaded and submitted only within “itself”.
But this creates a problem with the auto-logout and redirection to LogOn. The logout will fire when I, for example, press a new tab. This tab will then be rendered with the full LogOn-page, instead of refreshing the “parent/top” window. So the entire site is mirrored in one of the tabs (like often happens when using frames). The is no frame or iframe usage on the site though.
One way to perhaps solve it would be to itercept the ajax-call, maybe in the OnBegin, to check if the user is logged in. If not redirect the entire window url to /Account/LogOn. I’m not sure on how to accomplish this though, or if it’s the best way to go. Any ideas on execution or tips for better handling of this?
Some code examples:
Edit.cshtml, snippet: the tabs
<div id="tabs">
<ul>
<li><a href="@Url.Action("PatientGeneralTab", new { guid = @Model })"><span>General</span></a></li>
<li><a href="@Url.Action("PatientVisitTab", new { guid = @Model })"><span>Visit</span></a></li>
<li><a href="@Url.Action("PatientDiaryTab", new { guid = @Model })"><span>Treatment</span></a></li>
<li><a href="@Url.Action("PatientReactionTab", new { guid = @Model })"><span>Adverse Drug Reaction</span></a></li>
</ul>
</div>
General.cshtml, partial, snippet: Ajax.BeginForm()
@using (Ajax.BeginForm("StoreGeneral",
new { },
new AjaxOptions { HttpMethod = "POST", OnBegin = "Saving", OnSuccess = "SavedOk(); reloadPatientHeader();" },
new { id = "form-general" }))
{
form content here.
}
Web.config, authentication
<authentication mode="Forms">
<!-- TODO: Change back to 60 -->
<forms loginUrl="/Account/LogOn" timeout="2" />
</authentication>
Not sure if I need to post any other code-snippets. If so just let me know.
Edit
I stumbled on this question that has similar problems to mine. But I can’t add any code to the controllers since the entire controller-class is wrapped in “[Authorize(Roles=”xxx,yyy”)]”, so the check for login happens before the actual controller actions.
I tried to intercept the call in the AccountController instead, under “LogOn”, but then it just ends up in an infinite loop 🙂
public ActionResult LogOn()
{
bool isAjaxRequest = Request.Headers["X-Requested-With"] == "XMLHttpRequest";
if (isAjaxRequest && !Request.IsAuthenticated)
{
//Response.Headers["X-Requested-With"] = "";
return RedirectToAction("LogOn");
}
return View();
}
The solution
For reference, this is what I ended up using:
public ActionResult LogOn()
{
bool isAjaxRequest = Request.Headers["X-Requested-With"] == "XMLHttpRequest";
if (isAjaxRequest && !Request.IsAuthenticated)
{
return JavaScript("window.location = '/Account/LogOn'");
}
return View();
}
Try using
to detect ajax requests. It’s an extension method in System.Web.Mvc.
Or you can check manually:
With this you can do your intercept and test for authentication, and act accordingly. You could either choose not to show layout or stop the whole request and send to login page instead.