在ajax调用中处理会话超时

我正在使用jQuery进行ajax调用以执行asp.net mvc控制器操作:

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult GetWeek(string startDay)
        {
            var daysOfWeek = CompanyUtility.GetWeek(User.Company.Id, startDay);
            return Json(daysOfWeek);
        }

当会话超时时,此调用将失败,因为用户对象存储在会话中。 我创建了一个自定义授权属性,以检查会话是否丢失并重定向到登录页面。 这适用于页面请求,但它不适用于ajax请求,因为您无法从ajax请求重定向:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeUserAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (!httpContext.Request.IsAjaxRequest())
            {//validate http request.
                if (!httpContext.Request.IsAuthenticated
                    || httpContext.Session["User"] == null)
                {
                    FormsAuthentication.SignOut();
                    httpContext.Response.Redirect("~/?returnurl=" + httpContext.Request.Url.ToString());
                    return false;
                }
            }
            return true;
        }
    }

我在另一个线程上读到,当用户未通过身份验证并且发出ajax请求时,应该将状态码设置为401(未授权),然后在js中检查并将其重定向到登录页面。 但是,我无法得到这个工作:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (Request.IsAjaxRequest() && (!Request.IsAuthenticated || User == null))
            {
                filterContext.RequestContext.HttpContext.Response.StatusCode = 401;
            }
            else
            {
                base.OnActionExecuting(filterContext);
            }
        }

基本上,它会将它设置为401,但随后它将继续进入控制器操作并将对象引用设置为未设置为对象错误的实例,然后将错误500返回给客户端js。 如果我更改我的自定义Authorize属性以验证ajax请求,并为那些未通过身份验证的用户返回false,这会使ajax请求返回我的登录页面,这显然不起作用。

我如何得到这个工作?


您可以编写一个自定义的[Authorize]属性,它将返回JSON,而不是在未经授权的访问情况下抛出401异常,这将允许客户端脚本优雅地处理场景:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new JsonResult
            {
                Data = new 
                { 
                    // put whatever data you want which will be sent
                    // to the client
                    message = "sorry, but you were logged out" 
                },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

然后用它和客户端装饰你的控制器/动作:

$.get('@Url.Action("SomeAction")', function (result) {
    if (result.message) {
        alert(result.message);
    } else {
        // do whatever you were doing before with the results
    }
});

我不会将JsonRequestBehavior更改为AllowGet。 相反,我建议:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class MyAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        OnAuthorizationHelp(filterContext);
    }

    internal void OnAuthorizationHelp(AuthorizationContext filterContext)
    {

        if (filterContext.Result is HttpUnauthorizedResult)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.HttpContext.Response.StatusCode = 401;
                filterContext.HttpContext.Response.End();
            }
        }
    }
}

并添加全局js ajax错误处理程序:

   $(document).ajaxError(function (xhr, props) {
        if (props.status === 401) {
            location.reload(); 
        }
   }

尽管这已经很好地回答了,但如果您使用.NET 4.5,我认为这是最短和最甜蜜的答案。 称为SuppressFormsAuthenticationRedirect的小属性已添加。 设置为true,它不会执行302重定向登录页面。

http://msdn.microsoft.com/en-us/library/system.web.httpresponse.suppressformsauthenticationredirect.aspx

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AjaxAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // returns a 401 already
        base.HandleUnauthorizedRequest(filterContext);
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            // we simply have to tell mvc not to redirect to login page
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
        }
    }
}

假设你打算处理ajax请求失败/错误回调,在这个回调中你将得到一个401 Unauthorized。

链接地址: http://www.djcxy.com/p/12441.html

上一篇: Handling session timeout in ajax calls

下一篇: ASP.NET MVC 2 and authentication using WIF (Windows Identity Foundation)