在Ajax调用中处理会话超时

我正在做一个Ajax调用使用jQuery的一个asp.net mvc控制器行动:

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

会话超时时,由于用户对象存储在会话中,所以此调用将失败。 我创build了一个自定义的授权属性,以检查会话是否丢失,并redirect到login页面。 这适用于页面请求,但是它不适用于Ajax请求,因为您不能从ajax请求redirect:

 [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; } } 

我读了另一个线程,当用户没有通过身份validation,你做了一个Ajax请求,你应该设置状态代码401(未经授权),然后在js中检查,并redirect到login页面。 但是,我无法得到这个工作:

 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属性来validationajax请求,并为那些未经过身份validation的返回false,这使得ajax请求返回我的login页面,这显然不起作用。

我如何得到这个工作?

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

 [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。 相反,我build议:

 [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 ajaxerror handling程序:

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

即使这已经过去了,我认为如果你使用的是.NET 4.5,这是最短和最甜蜜的答案。 称为SuppressFormsAuthenticationRedirect的小属性已被添加。 设置为true,它不会执行302redirectlogin页面。

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请求失败/错误callback,你会得到一个401未经授权。

我有一个类似的问题,并发现这一点

强制ASP.NET返回401代码,而不是在返回响应之前返回任何JSON。 在Global.asax

 protected void Application_EndRequest() { var context = new HttpContextWrapper(Context); if (context.Request.IsAjaxRequest() && context.Response.StatusCode == 302) { Context.Response.Clear(); Context.Response.Write("**custom error message**"); Context.Response.StatusCode = 401; } } 

然后,你可以让客户端在JavaScript / jQuery中处理它,或者你正在使用的任何东西

在母版页上添加这个jQuery脚本————

 <script type="text/javascript"> $.ajaxSetup({ statusCode: { 403: function () { window.location.reload(); } } }); OR $.ajaxSetup({ error: function (x, e) { if (x.status == 403) { window.location.reload(); } } }); </script> 

在项目中添加一个名为TraceFilter的cs文件,然后编写一个inheritance到ActionFilterAttribute的SealFilter类TraceFilterAttribute。 在你的项目的App_Start文件夹下的FilterConfig.cs中添加TraceFilterAttribute类,方法如下:

filters.Add(new TraceFilterAttribute());

在TraceFilterAttribute类中覆盖方法OnActionExecuting()。 这将自动检查会话,如果find会话null,然后调用母版页中可用的脚本,并从他们你可以去你的select页面。

 [AttributeUsage(AttributeTargets.All)] public sealed class TraceFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext != null) { HttpSessionStateBase objHttpSessionStateBase = filterContext.HttpContext.Session; var userSession = objHttpSessionStateBase["etenetID"]; if (((userSession == null) && (!objHttpSessionStateBase.IsNewSession)) || (objHttpSessionStateBase.IsNewSession)) { objHttpSessionStateBase.RemoveAll(); objHttpSessionStateBase.Clear(); objHttpSessionStateBase.Abandon(); if (filterContext.HttpContext.Request.IsAjaxRequest()) { filterContext.HttpContext.Response.StatusCode = 403; filterContext.Result = new JsonResult { Data = "LogOut" }; } else { filterContext.Result = new RedirectResult("~/Admin/GoToLogin"); } } } } } 

这里是我如何在我的自定义授权中以如此简单的方式处理这个问题,我检查会话是否已经结束,并将其作为未授权的布尔值来处理,以检查它是否真正被authentication但未被授权(redirect到未授权页面)或者由于会话超时而未validation身份(redirect到login)

  private bool ispha_LoggedIn = false; protected override bool AuthorizeCore(HttpContextBase httpContext) { ispha_LoggedIn = false; var session = httpContext.Session; bool authorize = false; if (httpContext.Session["authenticationInfo"] == null) { return authorize; } using (OrchtechHR_MVCEntities db = new OrchtechHR_MVCEntities()) { UserAuthenticationController UM = new UserAuthenticationController(); foreach (var roles in userAssignedRoles) { authorize = UM.IsUserInRole(httpContext.User.Identity.Name, roles); if (authorize) { return authorize; } } } ispha_LoggedIn = true; return authorize; } protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (ispha_LoggedIn==false) { filterContext.Result = new RedirectResult("~/UserAuthentication/LogIn"); } else { filterContext.Result = new RedirectResult("~/Dashboard/UnAuthorized"); } } 

希望如果这引导了某人,并请如果有评论它欣赏知道他们虽然。

您可能想要尝试抛出HttpException并在您的JavaScript中捕获它。

 throw new HttpException(401, "Auth Failed") 

如果会话过期,则返回ajax

 <script> $(function(){ location.reload(); }); </script>