MVC 3 / Jquery AJAX / Session Expires / C# - 在 ajax 调用期间处理会话超时

Posted

技术标签:

【中文标题】MVC 3 / Jquery AJAX / Session Expires / C# - 在 ajax 调用期间处理会话超时【英文标题】:MVC 3 / Jquery AJAX / Session Expires / C# - Handling session timeout durng ajax call 【发布时间】:2012-05-22 08:45:25 【问题描述】:

我有一个对 MVC 的 ajax 调用,它返回一个局部视图。这一切都很好,直到会话结束或 cookie 过期。当我进行 ajax 调用时,它会在一个用于局部视图的 div 中显示内容。如何在 ajax 调用期间检测到我的会话已过期并正确重定向到全屏/页面

【问题讨论】:

我也遇到了同样的问题,你找到解决办法了吗? 【参考方案1】:

我建议将您的所有请求封装到一个包装器元素中:

public class JsonResponse<T>

    public JsonResponse()
    
    

    public JsonResponse(T Data)
    
        this.Data = Data;
    

    public T Data  get; set; 
    public bool IsValid  get; set; 
    public string RedirectTo  get; set; 

您要发送给客户的模型在 Data 中。

为了填充 RedirectTo,我在 Global.Asax 中使用了 GlobalAuthorize 属性并添加了 handle for HandleUnauthorizedRequests。

public sealed class GlobalAuthorize : AuthorizeAttribute

    protected override void HandleUnauthorizedRequest
      (AuthorizationContext filterContext)
    
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        
            filterContext.Result = new JsonResult
            
                Data = new JsonResponse<bool>
                       
                           IsValid = false,
                           //RedirectTo = FormsAuthentication.LoginUrl
                           RedirectTo = "/"
                       ,
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            ;
        
        else
        
            base.HandleUnauthorizedRequest(filterContext);
        
     

此外,我已将 所有 Ajax 请求封装到一个检查RedirectTo 的函数中。

function global_getJsonResult(Controller, View, data, successCallback, completeCallback, methodType)

    if (IsString(Controller)
        && IsString(View)
        && !IsUndefinedOrNull(data))
    
        var ajaxData;
        var ajaxType;

        if (typeof (data) == "string")
        
            ajaxData = data;
            ajaxType = "application/x-www-form-urlencoded"
        
        else
        
            ajaxData = JSON.stringify(data);
            ajaxType = "application/json; charset=utf-8";
        
        var method = 'POST';

        if (!IsUndefinedOrNull(methodType)) 
        
            method = methodType;
        

        var jqXHR = $.ajax(
            url: '/' + Controller + '/' + View,
            data: ajaxData,
            type: method,
            contentType: ajaxType,
            success: function(jsonResult)
            
                if (!IsUndefinedOrNull(jsonResult)
                    && jsonResult.hasOwnProperty("RedirectTo")
                    && !IsUndefinedOrNull(jsonResult.RedirectTo)
                    && jsonResult.RedirectTo.length > 0)
                
                    $.fn.notify('error', 'Login Expired', 'You have been inactive for a prolonged period of time, and have been logged out of the system.');
                    window.setTimeout(function()  window.location = jsonResult.RedirectTo , 5000);
                
                else if (IsFunction(successCallback))
                
                    successCallback(jsonResult, Controller + '/' + View);
                
            ,
            error: function(jqXHR, textStatus, errorThrown)
            
                if (errorThrown != 'abort')
                
                    $.fn.notify('error', 'AJAX Connection Error', textStatus + ': ' + errorThrown);
                

            ,
            complete: function(jqXHR, textStatus)
            
                if (IsFunction(completeCallback))
                
                    completeCallback(jqXHR, textStatus, Controller + '/' + View);
                
            
        );

        return jqXHR;
    

【讨论】:

我尝试使用你的方式,我的 HandleUnauthorizedRequest 完美运行,但它从来没有出现在 global_getJsonResult() 方法中,你能给我一个你如何封装你的 jquery 方法的例子吗? 不确定你的意思。上面的例子有一个封装ajax请求的方法,在我的JS代码中所有的请求都使用这个方法。【参考方案2】:

您可以使用 javascript 在客户端上创建一个计时器,该计时器将在会话超时时向用户显示一个对话框。您只需将计时器的值设置为会话超时。然后在 ajax 请求时,它也会重置倒计时。

var g_sessionTimer = null;
function uiSessionInit() 
    id = "uiTimeout";
    timeout = 3600000 * 24; // 1 day timeout
    uiSessionSchedulePrompt(id, timeout);
    $('body').ajaxStart(function () 
        // reset timer on ajax request
        uiSessionSchedulePrompt(id, timeout);
    );

function uiSessionSchedulePrompt(id, timeout) 
    if (g_sessionTimer)
        clearTimeout(g_sessionTimer);
    g_sessionTimer = setTimeout(function ()  uiSessionExpiring(id); , timeout);

function uiSessionExpiring(id) 
    // create a dialog div and use this to show to the user
    var dialog = $('<div id="uiTimeout"></div>').text("Your session with has timed out. Please login again.");
    $('body').append(dialog);
    $('#uiTimeout').dialog( 
           autoOpen: true, 
           modal: true, 
           title: 'Expired Session', 
           buttons:  
                "OK": function()
                    $(this).dialog('close'); 
                
           ,
           close: uiSessionDialogClose
     );


function uiSessionDialogClose()
    // take user to sign in location
    location = 'http://www.mypage.com'; 

【讨论】:

【参考方案3】:

已经 8 年了,但我刚刚遇到了一个类似的问题,即在用户的身份验证 cookie 过期后进行的将部分视图加载到模式中的 Ajax 调用会导致完整的登录页面被加载到模式中.我就是这样解决的。

首先,我在我的登录页面上添加了一个隐藏控件。 value 不是严格要求的,但我认为它使标记更具可读性:

<input id="isLoginPage" type="hidden" value="true" />

然后我像这样修改了 Ajax 调用。我正在使用 jQuery,但同样的原理也适用于普通的旧 Javascript:

$.ajax(
    url: `/mypartialview`,
    type: "GET",
    success: function (data) 
        var $modal = $("#myModal");
        $modal.find(".modal-content").html(data);
        if ($modal.find("#isLoginPage").length > 0) 
            window.location.replace("/");
        
        $modal.modal("show");
    
);

这是基于如果用户的身份验证已过期,MVC 的默认行为是返回登录页面,所以我“嗅探”Ajax 调用返回的视图以获取 isLoginPage 隐藏输入,如果找到,我知道登录页面已经返回,所以我只是将用户重定向到应用程序的根目录,然后 MVC 将重定向到主登录页面。

如果您的应用程序的根目录允许匿名访问,您可以将 window.location.replace("/") 替换为应用程序登录页面的路径,例如window.location.replace("/account/login").

通过这项工作,我将解决方案封装在一个函数中以简化事情并避免重复自己:

function handleAjaxData($container, data) 
    $container.html(data);
    if ($container.find("#isLoginPage").length > 0) 
        window.location.replace("/");
    

然后我可以像这样在我的 Ajax 调用中使用它:

$.ajax(
    url: `/mypartialview`,
    type: "GET",
    success: function (data) 
        var $modal = $("#myModal");
        handleAjaxData($modal.find(".modal-content"), data);
        $modal.modal("show");
    
);

您显然可以更进一步,将 Ajax 调用本身包含在函数中,但在我的情况下,这会涉及一些复杂的回调,所以我没有打扰。

【讨论】:

以上是关于MVC 3 / Jquery AJAX / Session Expires / C# - 在 ajax 调用期间处理会话超时的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 3 - Ajax.BeginForm 与 jQuery 表单插件

使用 WIF 和 jquery ajax 请求时 ASP.NET MVC 3 中的会话 Cookie 过期处理

asp.net mvc 接收jquery ajax发送的数组对象

AJAX 和 jQuery 与 MVC

如何在MVC应用程序中使用Jquery

MVC4 AspNet MVC下的Ajax / 使用JQuery做相关的Ajax请求