I am building a web application using .net MVC 4.
I have ajax form to edit data.
If the user is idle for 15 mins it will expire the session of the user. When that happens if user click edit button it loads the login page inside the partial content hence now the current session expires.
Edit Link - cshtml code
#Ajax.ActionLink("Edit", MVC.Admin.Material.ActionNames.TagEditorPanel, MVC.Admin.Material.Name, new { isView = "false", id = Model.ID.ToString() }, new AjaxOptions { HttpMethod = "GET", UpdateTargetId = "materialTagBox", InsertionMode = InsertionMode.Replace }, new { #class = "editlinks" })
Controller/Action Code
[Authorize]
public virtual ActionResult TagEditorPanel(bool isView, int id)
{
//do something
return PartialView(MVC.Admin.Material.Views._tag, response);
}
Web.config
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
I understand why it is happening. I don't know how to resolve it. I want to prevent it and I want to redirect user to login page directly. How can I achieve this?
Thanks inadvance..!!!
Maybe a hacky answer, but you can change the redirect location in forms authentication to a page that sets the window location to the login page with javascript.
Web Config
<authentication mode="Forms">
<forms loginUrl="~/Account/RedirectToLogin" timeout="2880" />
</authentication>
Account Controller
public ActionResult RedirectToLogin()
{
return PartialView("_RedirectToLogin");
}
_RedirectToLogin View
<script>
window.location = '#Url.Action("Login", "Account")';
</script>
The issue is your call is intercepted by [Authorize] and sends the login page even before your action method code is called. One way to sort this out is to create a custom action filter to check the timeout and do a hard redirect to login page. Following post has a good write up which may help you in creating and registering the filter
http://www.codeblockdrive.com/2012/12/mvc-custom-filters-session-timeout.html
Best of luck
You may want to check the answer to this (similar) question.
ASP.NET MVC Partial view ajax post?
Basically it says that you should avoid making ajax calls to functions that may redirect because of this and other problems.
You can avoid the problem that you are having by authorizing / checking the expiration manually in your function, and then returning redirect information that can be applied to the whole page.
I have used this approach, and it works well.
Inspired by kramwens answer, one could avoid making an extra RedirectToLogin view (and controller action) and just put the following in you original Login view:
<script>
if (window.location != '#string.Format("{0}://{1}{2}",Request.Url.Scheme, Request.Url.Authority,Url.Content("~/Account/Login"))')
window.location = '#Url.Action("Login", "Account")';
</script>
This tests the current window.location and if it is not as expected, it sets it as expected.
I know, my js is a bit hacky and crappy, but it does the work :)
I Have simple way find for partial view session expired.
Simple One Action created then this view java script windows.load() call then url will be pass to this login page.
//in Controller one Action Created.
<script type="text/javascript">
window.location = '#Url.Action("Login", "LogIn")';
</script>
Public ActionResult SessionExpire()
{
return View();
}
//Redirect to login from partail view after session is null:
return Redirect("~/OrderPlace/Sessionview");
My solution is to use some c# code whenever possible. I can get the controller and view name, check to see of they are what they should be, and if not redirect to the proper.
var controllerName = ViewContext.RouteData.GetRequiredString("controller");
var actionName = ViewContext.RouteData.GetRequiredString("action");
I then use the following to go to the proper URL:
if (controllerName != "members" && actionName != "logon")
{
#{ Response.Redirect("~/Members/Logon");}
}
Related
I am working on an application written in ASP.NET MVC5 which require the user to be log in. The authentication works with Central Authentication Service (CAS). On the homepage, I have several partial views :
Home page with partial views
I call a controller's action when I want to update the user's data.
It's working well, until the CAS session expires. If I try to refresh the partial views, I get an error :
"OPTIONS https://example.com/CAS/Authentication 403 (Forbidden)"
"Failed to load https://example.com/CAS/Authentication: Response for preflight has invalid HTTP status code 403"
I think it comes from the use of Ajax to refresh the partial view and it returns me the login page, which is not on the same domain. How can I overcome this issue ?
In my View I send the datas to the Controller with Ajax.BeginForm() and my controller returns a partial view, so that I don't need to completely refresh the page.
To overcome the Cross Origin Request error, I needed to handle the Ajax response. Instead of letting the login page being returned in the partial view, I call a Javascript function on the OnComplete event, checking the status code of the response.
In my partial view :
AjaxOptions ajaxOptions = new AjaxOptions
{
HttpMethod = "POST",
OnComplete = "redirectToLoginPage"
};
using (Ajax.BeginForm("ActionName", "ControllerName", null, ajaxOptions))
{
<button type="submit">Submit</button>
}
On click on submit, it will execute the action "ActionName" from the controller "ControllerName". Then, it will fire the Javascript function "redirectToLoginPage", which is :
function redirectToLoginPage(xhr) {
if (xhr.status == 200) {
//Whatever
}
else
{
window.location.replace("https://login.example/");
}
}
This do the trick.
I have a problem regarding those tutorials :
https://msdn.microsoft.com/en-us/library/xdt4thhy%28v=vs.140%29.aspx
I ve create my own site with those tips, so on my HTML file, I ve of course insert inside the form :
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true"></asp:ScriptManager>
I've create a Logon.aspx page in order to put the login form, and by click, the button call a javascript function login():
<script type="text/javascript">
function login() {
var user = $('#username').val();
var password = $('#password').val();
PageMethods.login_GO(user, password, ok, ko);
function ok(result) {
alert(result);
}
function ko(result) {
alert('Cannot process your request at the moment, please try later.');
}
}
</script>
then the javascript function call a behind code method (inside the Logon.aspx.cs file)
[WebMethod]
public string login_GO(string user, string password)
{
if (user == "cool" && password == "whau")
{
FormsAuthentication.RedirectFromLoginPage(user, true);
return "done";
}
else
{
return "KO";
}
}
The only answer I have is an alert messagebox from the browser:
Cannot process your request at the moment, please try later.
Why do you think this method doesnt work ?
I mean normally I dont need anything else isnt ?
Thanks in advance !
EDIT:
Before I started to debug the code, I decide to disable the Authentication feature in the Web.config configuration (I only put a comment on all those lines below) :
<authentication mode="Forms">
<forms loginUrl="Logon.aspx" name=".ASPXFORMSAUTH" defaultUrl="PlazaMonitor.aspx" >
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>-->
So now, I can call the login_GO method on the behind code (Logon.aspx.cs).
Every works fine, but not the Authentication (because I disabled it)
The goal of all of this, is to authenticate an user using a behind code method, so if I need to be Authenticated before I use the Authentication Method I m going to be crazy ^^ !
EDIT :
I just understand, EVERY ressource should be disabled until you are AUTHENTICATE, so even the WebMethod used to be authenticate is disabled !
Do you know where (in Web.config certainely) we could change/allow the good ressources we need ?
Thanks in advance for your help ;) !
I have created an asp.net mvc razor application, in which I load a partial view in a div, which can be accessed after login.
<% using (Ajax.BeginForm("Showproducts", "Home", new AjaxOptions {
UpdateTargetId = "resdiv", OnBegin = "fstart()", OnSuccess = "fend()"
}, new { id = "_myform" }))
{ %>
.....
<% } %>
When a user leaves their computer for a long time (which makes the session time out automatically) and then clicks the submit button, the resdiv is filled with the full site with the login panel. I want to show the full site with login panel NOT in the resdiv. Is there any way to avoid this behavior?
Is there any way to avoid this behavior?
Yes, there is a way. I would recommend you reading the following blog post in which Phil Haack illustrates a very nice technique allowing you to override the Forms Authentication Module for AJAX requests and be able to send a 401 status code instead of redirecting to the login page.
Then on the client side you could use a global AJAX handler where you could test the status code and if it is 401 redirect to the logon page.
For example once you have installed the AspNetHaack NuGet you could add the following global error handler to your view:
<script type="text/javascript">
$(document).ajaxError(function(event, jqXHR, ajaxSettings, thrownError) {
if (jqXHR.status == 401) {
// not authenticated => redirect to login page:
window.location.href = '#FormsAuthentication.LoginUrl';
}
});
</script>
My first post...
When I use RedirectToAction the url in the browser doesn't change. How can I achieve this?
I'm switching over to ASP.NET MVC 3.0 (also using jQuery Mobile) after 10+ years using web forms. I'm about 8 weeks into it, and after several books and scouring Google for an answer, I'm coming up dry.
I have a single route defined in Global.asax:
routes.MapRoute(
"Routes",
"{controller}/{action}/{id}",
new { controller = "Shopping", action = "Index", id = UrlParameter.Optional }
I have a ShoppingController with these actions:
public ActionResult Cart() {...}
public ActionResult Products(string externalId) {...}
[HttpPost]
public ActionResult Products(List<ProductModel> productModels)
{
// do stuff
return RedirectToAction("Cart");
}
The url when I do a get and post (with the post having the RedirectToAction) is always:
/Shopping/Products?ExternalId=GenAdmin
After the post and RedirectToAction I want the url in the browser to change to:
/Shopping/Cart
I've tried Redirect, and RedirectToRoute but get the same results.
Any help would be greatly appreciated.
[Update]
I found that jQuery Mobile AJAX posts are the culprit here. If I turn off jQuery Mobile's AJAX it works.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script type="text/javascript">
// do not handle links via ajax by default
$(document).bind("mobileinit", function () { $.mobile.ajaxEnabled = false; });
</script>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0rc2/jquery.mobile-1.0rc2.min.css" />
The ordering of the above scripts is important. I had to include the script to jQuery first, then include the script to disable jQuery Mobile's use of AJAX and then include the script to jQuery Mobile.
I'd still like to find a way to use AJAX and have the url update properly. Or at the least be able to call jQuery Mobile's "loading" message (or bake my own).
I think I've found an answer. Buried deep in the jQuery Mobile documentation, there is information about setting the data-url on the div with data-role="page". When I do this, I get the nice jQuery Mobile AJAX stuff (page loading message, page transitions) AND I get the url in the browser updated correctly.
Essentially, this is how I'm doing it...
[HttpPost]
public ActionResult Products(...)
{
// ... add products to cart
TempData["DataUrl"] = "data-url=\"/Cart\"";
return RedirectToAction("Index", "Cart");
}
Then on my layout page I have this....
<div data-role="page" data-theme="c" #TempData["DataUrl"]>
On my HttpPost actions I now set the TempData["DataUrl"] so for those pages it gets set and is populated on the layout page. "Get" actions don't set the TempData["DataUrl"] so it doesn't get populated on the layout page in those situtations.
The only thing that doesn't quite work with this, is when you right-click... view source... in the browser, the html isn't always for the page you are on, which isn't unusual for AJAX.
Not sure if it is still actual, but in my case I wrote following helper method
public static IHtmlString GetPageUrl<TModel>(this HtmlHelper<TModel> htmlHelper, ViewContext viewContext)
{
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.Append("data-url='");
urlBuilder.Append(viewContext.HttpContext.Request.Url.GetComponents(UriComponents.PathAndQuery, UriFormat.UriEscaped));
urlBuilder.Append("'");
return htmlHelper.Raw(urlBuilder.ToString());
}
And then use it as follows:
<div data-role="page" data-theme="d" #Html.GetPageUrl(ViewContext) >
This way I don't need for every redirect action store a TempData. Worked for me fine both for Redirect and RedirectToAction. This would not work properly in case if you use method "View()" inside controller and return different view name, which will change UI, but will retain url.
Hope it helps
Artem
David, this was a big help to me. I just wanted to add that in my case I had to use the following format to get the Url to display in the correct form as my other url's:
TempData["DataUrl"] = "data-url=/appName/controller/action";
return RedirectToAction("action", "controller");
As a side note, I also found that when assigning the value to TempData["DataUrl"] I was able to leave out the escaped quotes and enter it exactly as above and it seems to be working fine for me. Thanks again for your help.
There is an issue on github
https://github.com/jquery/jquery-mobile/issues/1571
It has a nice solution without the need of TempData
I'm using jquerymobile and asp.net MVC3 razor. I'm somewhat new to this, but figuring things out, I have a very basic route table, with just the ignore route for .axd resources and a default route:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "", UrlParameter.Optional }
);
I have an action link that works in an .ascx page:
#Html.ActionLink("Log On", "LogOn", "Account", null, new { #class = "ui-btn-right" })
Now, when I get to the LogOn page, and I complete the account verification, I need to send them to the home page, /Home/Home which works if I type it in the address bar, but I can't seem to get my redirect working in the account controller: return RedirectToAction("Home", "Home");
Thanks for any help!
It sounds like maybe you're posting your form from /Account/LogOn via ajax. That means that when you return RedirectToAction("Home", "Home");, the page wouldn't change. So you just need to not use ajax on the form submit. If my guess is wrong, please post more code so we can get an idea of what the problem is.
It appears from the documentation that jQuery mobile handles form posts via ajax automatically. To prevent this, add the data-ajax="false" attribute to the form element. Documentation here: http://jquerymobile.com/test/docs/forms/forms-sample.html
Given what's written in documentation, could you put your code into a form element and setting its action property to /Account/LogOn ? In order to do that, you may have to convert your ActionLink into a button.
You can check for ajax request in controller:
if(Request.IsAjaxRequest())
{
//send json object and do navigate in client
return Json(new {IsLogged = true});
}
else
{
//send redirect html code to browser
return RedirectToAction("Home", "Home");
}
and in client side, check for json result if you post form by jQuery ajax.
I'm not use jquerymobile so I don't know how it work in client side.