How to handle session timeout in MVC3 in javascript? - asp.net-mvc-3

In my application this is how we are dealing with the session timeout till now
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="20" />
</authentication>
Now I want to deal session time out on client side, something like this
<authentication mode="Forms">
<forms loginUrl="showPopup();" timeout="20" />
</authentication>
Is that possible, or any other suggested way to achieve this?
Edit
I visited to other questions of the same type but could not get any real help from them.

In my application this is how we are dealing with the session timeout till now
Great, that's the correct way to define forms authentication in web.config
Is that possible
No, sorry, putting javascript in the loginUrl attribute is meaningless.
or any other suggested way to achieve this
From what I understand you are trying to display the LogOn form using some javascript function if the session has expired.
You should distinguish between 2 types of request to your server:
Standard synchronous requests (anchors, forms, redirects, ...)
Asynchronous requests (AJAX - done by using javascript)
In both cases on the server side you should protected actions that require authentication by decorating them with the [Authorize] attribute. For example:
[Authorize]
public ActionResult SomeAction()
{
...
}
Once you have secured your server you could start thinking about how to handle forms authentication cookie expiration or simply the case of an anonymous user attempting to call this action.
For the first case of standard synchronous calls to the server, the forms authentication module will intercept the request and if the user is not authenticated or his session expired ASP.NET will automatically redirect you to the LogOn page you have defined in the loginUrl attribute. It will also pass as a ReturnUrl query string parameter to this action which will be pointing to the originally requested url by the user and for which he was not authorized yet. This parameter could then be used to redirect him back to this page once he has authenticated.
Now the second case is a bit more difficult because since ASP.NET automatically redirects the request to the LogOn page you have no way of knowing inside your AJAX success callback that the user is not authorized and the server redirected the request to the LogOn page. Phil Haack wrote an excellent article on how you could prevent this redirect for AJAX request. I invite you to read this article now.
Alright, now that you have read the article and have installed his NuGet (Install-Package AspNetHaack), assuming you are using jQuery for your AJAX requests, you could subscribe to the .ajaxComplete() global event handler. Inside this handler you could test the server response code and if it is 401 it means that the user was not authorized. So you could act accordingly:
<script type="text/javascript">
$(document).ajaxComplete(function(event, xhr, ajaxOptions) {
if (xhr.status == 401) {
// the AJAX request failed because either the user was not
// authenticated or his session expired. So here you could
// do whatever you want. For example you could redirect him
// to the loginUrl defined in your web.config file:
window.location.href = '#FormsAuthentication.LoginUrl';
// you also have the possibility to show this logon form
// inside a popup or render it inline inside the page,
// by sending an AJAX request to this action and retrieving the
// corresponding partial
}
});
</script>

This configuration area is to configure server side behaviour, that happens when the server tries to handle a request where the session has expired. It is the result of a client -> server request for a page. As the client is a web browser and is by design disconnected from the server, you would have to include the logic you require in each page (probably in the main layout template) and then make AJAX calls at repeating intervals to the server to ascertain the user's session time-out state. The pop-up would also be handled on the client.
This area of configuration probably isn't going to help you reach your goal, I'd just remove the <forms> element altogether and look at solving the problem using AJAX calls to the server.

Related

Golang - Server Side Login Handling - how to resume request after login?

Currently, I’m developing a web app with server-side rendering using the Gin framework and I’m having a problem with login intercepting. When an HTTP GET request hits an endpoint, middleware is used to check the browser cookie and redirect the traffic to the login page. This works fine and after successful login, the user is always redirected to the dashboard page. My question is how I should redirect the user back to the originally requested URI instead of the dashboard page?
Also, a bit more complex scenario is on HTTP POST. It looks like the HTTP POST method doesn’t work quite well with a redirect. Also, how would I resume the request with the same post request after the user successfully login?
Thanks for the help!
For the HTTP GET scenario, this one is easy, you need to remember the original URL somewhere. The are a few ways you could go about this:
Store the URL in session information(if any is available, you do need sessions for non-authenticated users)
Store it in a query string, for example, redirect to example.com/login?original=https%3A%2F%2Fexample.com%2Fanother-page. Your login page can look for the query parameter and include it in the login form or make sure that the action of the login form matches the given URI. On a successful login attempt you can get the original URL form the query param and set it as the Location.
Store the original URL in a cookie, upon successful login you can just check the cookie value and use that.
As for the HTTP POST scenario. If you just want to redirect the same POST request to a different URL you can use a 307 Temporary redirect. A 307 will preserve the request body and method and not turn it into a GET request like a 303 See Other or 302 Found.
Resuming the original POST after showing the login screen and after a successful login is a little more complex. When you redirect to the login page you interrupt the flow of the user, maybe it is better to let the user re-post their request after logging in, instead of doing it for them.
Having said that, it is technically possible. We require two steps, first is storing all the data to recreate the request. Then after login completion we can render a form with this saved data and use javascript to submit the form. By adding:
<script>document.getElementById("myForm").submit();</script>
After your form, the browser will submit the form after loading the javascript, thus recreating the original POST.
The storage part can be done via the server side session or a cookie.

Redirect user to Login page, from an jquery ajax request

Iam using custom Authorize filter to on my action method to check if user has an access to it.
If user does not have an access then user is redirected to Unauthorize page.
The problem iam facing here is iam using Jquery Ajax request to call that action method. Everything works well if the user has an access. But if the user does not have an access the code is not able to bind the View("Unauthorize") and it display the existing view on the browsers screen;
Any suggestions would be helpful.
Thanks.
The thing is that ajax requests can not send a redirect response. You can instead either return a status code that tells the calling javascript to redirect or simply change the Response.ContentType to application/javascript and use window.location = "newUri" as the response body.

Ajax based application and want to redirect to login page after session expired

Here I am make one application which is fully remote based.
only once all js and css loaded. So I want need solution for session expired.
Means when ajax request come to controller, it will be authenticated first, for session if session expired then I want to redirect to login page relogin.
[EDIT - #Brad]
Let's try and clarify your requirement..
1) make request to server via Ajax
2) server responds with HTTP 401, not authorized
3) Ajax recognises 401 status and redirects to Login page
4) login success,
5) then old request executed. means step 1 request executes.
6) but I want dont want to execute that step-1 request but want to execute home page everytime.
One approach is to have your Client side AJAX code check for a HTTP 401 response code which means that your users session has timeout and they are no longer logged in.
Using JQuery...
$.ajax({
type: "post", url: "/SomeController/SomeAction",
success: function (data, text) {
//...
},
error: function (request, status, error) {
// look for status of 401 and redirect to login
}
});
Of course you just have to make sure your web app is returning the appropriate status codes. I found this article on the subject to be thought provoking.
There is also some good information on a similar question
[EDIT]
OK, from your updated question at step 3) this is occuring over an ajax request and I am expecting that your user does not see a login page because your ajax handling code will receive the 401 response and you can decide not to display it. You can then redirect the users browser to your login URL of choice. In this case you would redirect to the home page, or configure your login page to accept an additional URL parameter to tell it where you want the user to be sent to once they have logged in.
You could use a filter interceptor before the request comes on to your action every time.
A better way to do this is by using the apache-shiro authentication plugin available for grails.
See this : Apache Shiro Integration for Grails
Install this in your application and configure it. Its simple and takes care of most of your authentication requirements.

ASP.NET MVC - Failed to load resource in Response.Redirect

I noticed if my session expired whilst on my site and then I clicked on an Ajax.ActionLink, the login page would be displayed in a PartialView. I've created an override of the OnActionExecuting method like so:
protected override void OnActionExecuting(ActionExecutingContext ctx)
{
if (!ctx.HttpContext.User.Identity.IsAuthenticated)
{
if (ctx.RequestContext.HttpContext.Request.IsAjaxRequest())
{
//ctx.RequestContext.HttpContext.Response.RedirectToRoute(new { controller = "Account", action = "LogOn" });
ctx.RequestContext.HttpContext.Response.Redirect(Url.RouteUrl(new { controller = "Account", action = "LogOn" }));
}
}
}
This checks if the User is Authenticated and then if the request is an AjaxRequest. It will then redirect the user to the LogOn method in my Account controller if they're no longer authenticated for an Ajax actionlink. The problem is I get "Failed to load resource" in the console.
This checks if the User is Authenticated and then if the request is an
AjaxRequest. It will then redirect the user to the LogOn method in my
Account controller if they're no longer authenticated for an Ajax
actionlink
Yes, but if you configured your Ajax.ActionLink or Ajax.BeginForm to update some DOM element with the results of the AJAX request using the AjaxOptions, it doesn't really matter if you are redirecting on the server. The AJAX request will simply follow the redirect and insert the resulting HTML you redirected to (/Account/LogOn) inside the DOM element.
So redirecting from an AJAX request won't solve your problem. As you know the whole point of an AJAX request is to stay on the same page (the address bar never changes).
If you wanted to handle the authentication cookie expired condition in a proper way within your AJAX requests you will have to perform the redirect on the client (using window.location.href). In order to achieve that you may take a look at the following blog post in which Phil Haack exposes a great technique allowing your server to send a 401 HTTP status code in this case instead of redirecting. Then on the client you could intercept this code (by subscribing to a global AJAX handler for example) and redirect to the logon page from the client.

AntiForgeryToken without forms authentication

We have a website that uses MVC3 and a custom authentication method that does not rely on forms authentication at all -- at least from what I can tell. In web.config we set
<authentication mode="None"></authentication>
and we never use/set HttpContext.User anywhere in code. The problem is when using #Html.AntiForgeryToken() in some cases the user gets this error message:
A required anti-forgery token was not supplied or was invalid
We centralize all anti-forgery checks in OnAuthorization with this code:
if (String.Compare(filterContext.HttpContext.Request.HttpMethod, "post", true) == 0)
{
var forgery = new ValidateAntiForgeryTokenAttribute();
forgery.OnAuthorization(filterContext);
}
That is where the exception occurs. We have defined a machineKey in web.config to prevent new keys being generated when the application pool recycles. This did not fix the problem.
Next we thought that maybe the client's browser is not sending cookies. We started logging cookies and noticed that in some cases the RequestVerificationToken_Lw cookie is sent, but in others is not -- even though other cookies, like the ones made by Google Analytics, are sent along just fine. Could it be something in the browser is stripping out some cookies and leaving others in?
It seems like the anti-forgery token depends on forms authentication. Is this the case? Any way to keep using the AntiForgeryToken when not using forms authentication in a reliable way. Keep in mind that the method I described above works for more than 90% of cases, but we can't pinpoint why it doesn't work for some people.
Thoughts?
Thanks!
Do some users have this issue all the time? Or just some of the time? Also, does it work for some of the methods ALL the time or is it inconsistent for the same action method? Do you have any ajax calls? The default anti-forgery token implementation does not handle AJAX calls. But you can write some custom code to get it to work
Are you adding the antiforgery token inside of the form? The antiforgery token is stored on the client via a hidden HTML element so and not as a cookie. The other question would be what browser version are they using? Are can the upgrade to the latest?
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()...

Resources