使用ASP.NET MVC的json请求的401响应代码
如何禁用AJAX / JSON请求的标准ASP.NET处理401响应代码(redirect到login页面)?
对于网页是没关系的,但对于AJAX我需要得到正确的401错误代码,而不是好看302/200login页面。
更新 :有几个解决scheme,从菲尔哈克,PMM的ASP.NET MVC – http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot -want.aspx
如果HttpResponse.StatusCode
设置为401,但只有在findWeb.config的<authentication />
部分时,才开发ASP.NET运行时,以便始终将用户redirect。
删除身份validation部分将要求您实现redirect到您的属性login页面,但这不应该是一个大问题。
在传统的ASP.NET中,当用Ajax调用WebMethod时,会得到一个401的http响应代码。 我希望他们能在将来的ASP.NET MVC版本中改变它。 现在我正在使用这个黑客:
protected void Application_EndRequest() { if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest") { Context.Response.Clear(); Context.Response.StatusCode = 401; } }
我希望这两个表单身份validation,并返回一个未经过身份validation的Ajax请求401。
最后,我创build了一个自定义的AuthorizeAttribute并修饰了控制器方法。 (这是在.Net 4.5上)
//web.config
<authentication mode="Forms"> </authentication>
//控制器
[Authorize(Roles = "Administrator,User"), Response302to401] [AcceptVerbs("Get")] public async Task<JsonResult> GetDocuments() { string requestUri = User.Identity.Name.ToLower() + "/document"; RequestKeyHttpClient<IEnumerable<DocumentModel>, string> client = new RequestKeyHttpClient<IEnumerable<DocumentModel>, string>(requestUri); var documents = await client.GetManyAsync<IEnumerable<DocumentModel>>(); return Json(documents, JsonRequestBehavior.AllowGet); }
// authorizeAttribute
public class Response302to401 : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (!filterContext.HttpContext.User.Identity.IsAuthenticated) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { filterContext.Result = new JsonResult { Data = new { Message = "Your session has died a terrible and gruesome death" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet }; filterContext.HttpContext.Response.StatusCode = 401; filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate"; filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; } } //base.HandleUnauthorizedRequest(filterContext); } }
你也可以使用Global.asax来打断这个过程:
protected void Application_PreSendRequestHeaders(object sender, EventArgs e) { if (Response.StatusCode == 401) { Response.Clear(); Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx")); return; } }
我没有看到我们需要修改authentication模式或者authentication标签,就像当前的答案所说的那样。
遵循@TimothyLeeRussell的思想(谢谢),我创build了一个自定义的Authorize属性(@TimothyLeeRussell的问题是抛出一个exception,因为他试图改变filterContext.Result并生成一个HttpException,删除该部分,除了filterContext.HttpContext.Response.StatusCode = 401,响应代码总是200 OK)。 所以我最终通过结束更改后的响应来解决问题。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class BetterAuthorize : AuthorizeAttribute { protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) { if (filterContext.HttpContext.Request.IsAjaxRequest()) { //Set the response status code to 500 filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate"; filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true; filterContext.HttpContext.Response.End(); } else base.HandleUnauthorizedRequest(filterContext); } }
您可以select创build实现了IAuthorizationFilter
接口的自定义FilterAttribute
。
在这个属性中添加逻辑来确定请求是否应该返回JSON。 如果是这样,您可以返回一个空的JSON结果(或做任何你喜欢的),因为用户没有login。对于其他的响应,你可以像往常一样redirect用户。
更好的是,你可以重写AuthorizeAttribute
类的OnAuthorization
,所以你不必重新发明轮子。 添加上面提到的逻辑,如果filterContext.Cancel
为true,则拦截( filterContext.Result
将设置为HttpUnauthorizedResult
类的实例。
在Phil Haacks博客上阅读更多关于“ASP.NET MVC CodePlex Preview 4中的filter”的内容。 它也适用于最新的预览。
你可以在你的动作中调用这个方法,
HttpContext.Response.End();
例
public async Task<JsonResult> Return401() { HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; HttpContext.Response.End(); return Json("Unauthorized", JsonRequestBehavior.AllowGet); }
从MSDN :End方法导致Web服务器停止处理脚本并返回当前结果。 文件的其余内容不被处理。