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

Posted

技术标签:

【中文标题】使用 WIF 和 jquery ajax 请求时 ASP.NET MVC 3 中的会话 Cookie 过期处理【英文标题】:Session Cookies expiration handling in ASP.NET MVC 3 while using WIF and jquery ajax requests 【发布时间】:2012-06-18 11:10:27 【问题描述】:

我的项目我正在使用 WIF (但这对于这个问题的上下文并不重要。您可以使用替代框架来处理您的身份验证。问题是关于在执行 ajax 请求时处理身份验证失败) 。不过,就我而言,我编写了继承自 ClaimsAuthenticationManager 并处理身份验证的自定义服务器逻辑:

public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)

    if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
    
        // add some custom claims
    
    return incomingPrincipal;

现在,在我删除所有会话 Cookie 后,结束然后再次进入任何页面,我被重定向到 WIF 提供的登录页面,并要求我再次登录。一切正常。

但如果我改为发出 ajax 请求,则会出现错误,并被以下代码拦截:

$(document).ready(function () 
    $.ajaxSetup(
        error: function (XMLHttpRequest, textStatus, errorThrown)             
            // do something
        
    );
);

不幸的是,XMLHttpRequest 对象没有返回任何有意义的消息,基于此,我可以像其他人一样以任何其他方式处理这种错误。在这种特殊情况下,我只希望应用程序重定向到登录页面 - 就像正常请求一样。

在执行 ajax 调用时,将调用来自 ClaimsAuthenticationManager 的方法 AuthenticateIdentity.IsAuthenticated 返回 false,方法结束,一切都完成了。甚至 BaseController 中的 OnAuthorization 方法也没有被调用,所以我无法将任何状态传递给 ajax 结果对象。

protected override void OnAuthorization(AuthorizationContext filterContext)

    if (filterContext.HttpContext.Request.IsAjaxRequest() && !User.Identity.IsAuthenticated)
    
        //do something, for example pass custom result to filterContext
    
    base.OnAuthorization(filterContext);

如何解决这个难题?

【问题讨论】:

【参考方案1】:

我找到了一些关于此的资源(见答案底部),并与以下解决方案混为一谈:

在执行 ajax 请求时,我指定要返回 json:

$.ajax(
    url: action,
    type: 'POST',
    dataType: 'json',
    data: jsonString,
    contentType: 'application/json; charset=utf-8',
    success:
        function (result, textStatus, xhr) 
        
);

因为我的框架处理身份验证,当令牌过期时,它会将 http 状态 302 放入响应中。因为我不希望我的浏览器透明地处理 302 响应,所以我在 Global.asax 中捕获它,并将状态更改为 200 OK。此外,我添加了标头,指示我以特殊方式处理此类响应:

protected void Application_EndRequest()

    if (Context.Response.StatusCode == 302
        && (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
                    
        Context.Response.StatusCode = 200;
        Context.Response.AddHeader("REQUIRES_AUTH", "1");
    

响应内容没有正确序列化为json,导致解析错误。调用错误事件,在其中执行重定向:

$(document).ready(function () 
    $.ajaxSetup(
        error: function (XMLHttpRequest, textStatus, errorThrown) 
            if (XMLHttpRequest.getResponseHeader('REQUIRES_AUTH') === '1') 
                // redirect to logon page
                window.location = XMLHttpRequest.getResponseHeader('location');
            
            // do sth else
        
    );
);

更多解释请参见How to manage a redirect request after a jQuery Ajax call 和此处How do you deal with AJAX requests when user session expires, or where the request terminates in a 302。

更新:

与此同时,我想出了新的解决方案,在我看来要好得多,因为它可以应用于所有开箱即用的 ajax 请求(如果它们没有明显地重新定义 beforeSend 事件):

$.ajaxSetup(
    beforeSend: checkPulse,
    error: function (XMLHttpRequest, textStatus, errorThrown) 
        document.open();
        document.write(XMLHttpRequest.responseText);
        document.close();
    
);

function checkPulse(XMLHttpRequest) 
    var location = window.location.href;
    $.ajax(
        url: "/Controller/CheckPulse",
        type: 'GET',
        async: false,
        beforeSend: null,
        success:
            function (result, textStatus, xhr) 
                if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') 
                    XMLHttpRequest.abort(); // terminate further ajax execution
                    window.location = location;
                
            
    );

控制器方法可以是任何最简单的方法:

[Authorize]
public virtual void CheckPulse() 

Application_EndRequest() 和以前一样。

【讨论】:

以上是关于使用 WIF 和 jquery ajax 请求时 ASP.NET MVC 3 中的会话 Cookie 过期处理的主要内容,如果未能解决你的问题,请参考以下文章

jQuery:我可以在较长的 $.ajax 请求待处理时发送和接收 $.ajax 响应吗?

jquery ajax请求方式与提示用户正在处理请稍等,等待数据返回时loading的显示

jQuery之异步Ajax请求使用

jquery - 使用 .done()、.then() 和 .when() 以给定顺序发出 ajax 请求

使用 jQuery 在失败时重试 AJAX 请求的最佳方法是啥?

如何优化 Jquery 中的 ajax 请求? [关闭]