Checking for Session Expiry in Ajax Requests Using Asp.net MVC

We are currently implementing Ajax calls throughout our application and are looking for a universal solution to redirect users to the login page if their session has expired while attempting to execute an Ajax request. I have developed the following solution with assistance from this post - Handling session timeout in ajax calls

However, I am uncertain as to why the "HandleUnauthorizedRequest" event is not being triggered in my case.

Custom Attribute:

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class CheckSessionExpireAttribute :AuthorizeAttribute
    {
        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                var url = new UrlHelper(filterContext.RequestContext);
                var loginUrl = url.Content("/Default.aspx");

                filterContext.HttpContext.Session.RemoveAll();
                filterContext.HttpContext.Response.StatusCode = 403;
                filterContext.HttpContext.Response.Redirect(loginUrl, false);
                filterContext.Result = new EmptyResult();
            }
            else
            {
                base.HandleUnauthorizedRequest(filterContext);
            }

        }

    }

Implementing the custom attribute in a controller action:

 [NoCache]
 [CheckSessionExpire]
 public ActionResult GetSomething()
 {
  }

AJAX Call(JS part):

function GetSomething()
{
   $.ajax({
        cache: false,
        type: "GET",
        async: true,
        url: "/Customer/GetSomething",
        success: function (data) {

        },
        error: function (xhr, ajaxOptions, thrownError) {

        }
}

Web Config Authentication settings:

  <authentication mode="Forms">
      <forms loginUrl="default.aspx" protection="All" timeout="3000" slidingExpiration="true" />
    </authentication>

I have attempted to delete browser cookies before making an Ajax call to test, but the "CheckSessionExpireAttribute" event does not seem to be triggered. Any suggestions would be greatly appreciated.

Thanks,

@Paul

Answer №1

It seems like the issue you were facing involved your login page loading within an element designated for a different View via Ajax, or encountering an exception/error status code during an Ajax form post.

To address this, the annotation class must override not just the HandleUnauthorizedRequest method, but also another one. This will allow it to redirect to a JsonResult Action that provides parameters for the Ajax function to proceed accordingly.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class SessionTimeoutAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        IPrincipal user = filterContext.HttpContext.User;
        base.OnAuthorization(filterContext);
        if (!user.Identity.IsAuthenticated) {
            HandleUnauthorizedRequest(filterContext);
        }
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new RedirectToRouteResult(new
            RouteValueDictionary(new { controller = "AccountController", action = "Timeout" }));
        }
    }
}

Apply this annotation to your authentication Action so that each call is properly identified and receives the appropriate response.

[AllowAnonymous]
[SessionTimeout]
public ActionResult Login() { }

Next, create the redirected Json Action:

[AllowAnonymous]
public JsonResult Timeout()
{
    // Optionally display an error message upon loading the login page
    TempData["hasError"] = true;
    TempData["errorMessage"] = "Your session expired, please log-in again.";

    return Json(new
    {
        @timeout = true,
        url = Url.Content("~/AccountController/Login")
    }, JsonRequestBehavior.AllowGet);
}

Lastly, in your client function (using $.get()):

$(document).ready(function () {
    $("[data-ajax-render-html]").each(function () {
        var partial = $(this).attr("data-ajax-render-html");
        var obj = $(this);

        $.get(partial, function (data) {
            if (data.timeout) {
                window.location.href = data.url;
            } else {
                obj.replaceWith(data);
            }
        }).fail(function () {
            obj.replaceWith("Error: It wasn't possible to load the element");
        });
    });
});

This function replaces the specified html tag with content from the provided View address indicated by the data-ajax-render-html attribute. You can choose to load it within the tag using html() property instead of replaceWith.

Answer №2

It seems like the issue is specific to the client-side. When it comes to a web server, you can easily apply the traditional Authorize attribute on actions or controllers. This will verify if the request is authenticated (based on a valid authentication cookie or authorization header) and return an HTTP 401 error if not authenticated.

Keep in mind: If you send a request without authorization info, a session will be automatically recreated but the request will still not be authorized.

Resolution

Therefore, on the javascript client side, you need to manage the redirection (browsers usually handle this automatically, but with ajax, manual intervention is required).

$.ajax({
    type: "GET",
    url: "/Customer/GetSomething",
    statusCode: {
       401: function() {
          // Perform redirection to the login page
          window.location.href = '/default.aspx'
       }
    }
});

Answer №3

Upon reviewing and testing the code, it appears that the issue lies with the ajax call being incorrect.

I have made corrections to the Ajax code, please use the updated version below:

function GetSomething() {
        $.ajax({
            cache: false,
            type: "GET",
            async: true,
            url: "/Customer/GetSomething",
            success: function (data) {

            },
            error: function (xhr, ajaxOptions, thrownError) {

            }
        });
    }

Answer №4

The Function of HttpContext.Request.IsAjaxRequest()

For further insights on why an Ajax request may not be correctly identified, please refer to the following article.

XMLHttpRequest() not being detected as IsAjaxRequest?

It appears that the function requires a specific header value (X-Requested-With) in the request for it to return true.

You should analyze and monitor your traffic and headers sent to the server to verify if the browser is indeed sending this value.

But have you confirmed whether the code line is actually being executed? Consider debugging with breakpoints to examine the set values.

Regarding Session and Authentication

Authorization and session timeout do not always align perfectly. It is possible to grant authorization for a longer duration than the session, and even recreate the session if it expires, as long as the user remains authorized. If there are vital session data at risk, consider transferring or persisting them elsewhere.

Form Authentication cookies typically expire after 30 minutes, while the default Session timeout is 20 minutes.

Managing Session Timeout in ASP.NET

Issues with HandleUnauthorizedRequest Override

Answer №5

We regret to inform you that the desired solution cannot be achieved. The following are the reasons for this limitation:

  • In order to redirect users to a login page, there are two methods available: server-side redirection and client-side redirection.
  • Since you are utilizing Ajax in your situation, only the client-side redirection method can be utilized. This is because Ajax is primarily used for sending and retrieving data from the server, making it impossible to perform server-side redirection.
  • Furthermore, in order to achieve client-side redirection with Ajax, the server must provide information indicating the need to redirect the user to the login page. However, the global check session method can only return one type of response (e.g. Redirect("url here") or Json, Xml, Object, or string).
  • In conclusion, the global check session method cannot simultaneously return multiple types of responses.

As a recommendation, we propose the following solutions:

  • Solution 1: Avoid using Ajax altogether.
  • Solution 2: If you still wish to use Ajax, implement a server-side check session timeout method specific to each Ajax call made, rather than a global check. This means you will need to implement multiple checks corresponding to the number of Ajax calls being made.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why isn't my List<string> being retrieved from the MVC Controller in an $ajax request?

I am attempting to generate customized lists in my cshtml file through an ajax request. .ajax({ type: "GET", cache: false, url: "@Url.Action("getValidationLists")", contentType: "application/json", dataType: "json", ...

Issue: $injector:unpr Angular Provider Not Recognized

I've recently developed an MVC project and encountered an issue regarding the loading of Menu Categories within the layout. <html data-ng-app="app"> . . . //menu section <li class="dropdown" ng-controller="menuCategoriesCtrl as vmCat"> ...

Handling session expiration in ASP.NET MVC when making an AJAX call by redirecting to the login page

I'm currently learning ASP.NET MVC and I'm a newbie in it, so I'm struggling to find a solution for a specific problem. If anyone has encountered this issue before, I would appreciate any advice. Thank you! In my project, I am using ASP.NET ...

Extracting information from AJAX calls using a DataTable

When it comes to creating CRUD tables in school, I've always used scaffolding per page. However, I recently wanted to experiment with performing all operations without using Partial View. I decided to implement AJAX by following a tutorial on Everyth ...

Making an Ajax request to trigger a method within a controller

Here is the code snippet I wrote: $(function () { $("input#Submit1").on('click', function () { $.ajax({ url: 'Home/GetPort', method: 'GET' }); alert("test") ...

Sending dynamic boolean model property via AJAX dynamically

I am facing an issue while passing a property from my model to an AJAX form. The boolean value is resolving as "true/false" and causing problems in the process. $.ajax({ url: '/Projects/SearchTable2', type: "GET", data: { sub ...

The C# MVC Controller is having difficulty retrieving decimal or double values from an Ajax POST request

Having trouble sending decimal or double values via ajax to my C# MVC Controller. The values always come through as null, even though they work fine when sent as strings or integers. Why is this happening? When checking the client's request, the corre ...

How can I streamline a kendo UI MVC project by eliminating unnecessary components?

After switching my MVC 5 project to utilize Kendo UI, I've noticed a significant increase in the number of files being used. Since there is no need for supporting other cultures at the moment, can I confidently delete the files within the messages an ...

Ways to conceal the jqgrid thumbnail

I have a jqgrid that displays a large amount of dynamic data. I am looking for a way to hide the thumb of the vertical scrollbar in the jqgrid when scrolling using the mousewheel. Here is a basic example: var data = [ [48803, "DSK1", "", "02200220", "O ...

Steps to display the leave site prompt during the beforeunload event once a function has finished running

While facing a challenge with executing synchronous Ajax methods in page dismissal events, I discovered that modern browsers no longer support this functionality in the "beforeunload" event. To work around this issue, I implemented a new promise that resol ...

We were unable to load the resource because the server returned a 404 (Not Found) error. The EnterpriseMaster/BindNatureofAssignment feature is not functioning properly after being published

While the code is working perfectly fine on localhost, as soon as I publish it I encounter an error that prevents the table from loading. EnterpriseMaster/BindNatureofAssignment:1 Failed to load resource: the server responded with a status of 404 (Not ...

The MVC framework causing the Morris chart to omit the final xkey value

I am facing an issue with my Morris Chart where it is not displaying the last xkey value. Any thoughts on why this might be happening? https://i.stack.imgur.com/mHBQd.png Here is the data I am working with: [{"Date":"2016-07-17","Average":0.0},{"Date":" ...

What's the best way to display a bootstrap modal window popup without redirecting to a new page?

I am having trouble implementing a modal window that will display validation errors to the user when they submit a form. Currently, the window is opening as a new view instead of overlapping the existing form's view. How can I adjust my code so that t ...

Retrieving Data from a JSON File in ASP.NET MVC 4

After diving into learning ASP.NET MVC 4, I dabbled in some small projects... On my index page, my goal is to fetch a JSON file containing data and showcase it on the main page. In basic HTML and JavaScript, I utilize ajax for fetching or posting JSON da ...

The issue I am facing is that whenever I use an AJAX POST request,

I encountered an issue where the ajax post method was unable to pass a parameter to the controller, as the controller parameter always appeared as Null. Index.schtml: I attempted to initiate a new view via a parameter by triggering an element in HTML and ...

What is the reason behind ASP MVC model binder's preference for JSON in POST requests?

Is there a way to bind data to a model when sending a 'GET' request with JSON.stringify() using AJAX? Currently, the model value is always null when using 'GET', but it works fine with 'POST'. Are there any solutions for this ...

I am having trouble retrieving a JsonResult from an asp.net mvc controller using $resource in angular

I am new to Angularjs and trying to integrate it with asp.net mvc. I am facing an issue where I am unable to access an asp.net mvc controller to return a JsonResult using $resource in angular. Strangely, when I use $.getJson in JavaScript directly, it work ...