如何为AJAX / JSON请求禁用401响应代码的标准ASP.NET处理(重定向到登录页面)?
对于网页来说没关系,但是对于AJAX,我需要获得正确的401错误代码,而不是看起来好看的302/200登录页面。
更新: ASP.NET MVC的PM的Phil Haack有几个解决方案 - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx
答案 0 :(得分:24)
在经典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;
}
}
答案 1 :(得分:18)
开发ASP.NET运行时,以便在HttpResponse.StatusCode
设置为401时始终重定向用户,但仅当找到Web.config的<authentication />
部分时才会重定向。
删除身份验证部分将要求您实现重定向到属性中的登录页面,但这不应该是一个大问题。
答案 2 :(得分:9)
我想要两种Forms身份验证,并为未经过身份验证的Ajax请求返回401.
最后,我创建了一个自定义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);
}
}
答案 3 :(得分:2)
你也可以使用Global.asax来中断这个过程:
protected void Application_PreSendRequestHeaders(object sender, EventArgs e) {
if (Response.StatusCode == 401) {
Response.Clear();
Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx"));
return;
}
}
答案 4 :(得分:2)
我没有看到我们必须修改身份验证模式或身份验证标记,就像当前的答案所说的那样。
遵循@TimothyLeeRussell的想法(感谢方式),我创建了一个自定义的Authorize属性(@TimothyLeeRussell的问题是抛出一个异常,因为他试图更改filterContext.Result并生成一个除了filterContext.HttpContext.Response.StatusCode = 401之外,HttpException和删除该部分,响应代码始终为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);
}
}
答案 5 :(得分:1)
您可以选择创建实施FilterAttribute
界面的自定义IAuthorizationFilter
。
在此属性中,您添加逻辑以确定请求是否应返回JSON。如果是这样,您可以返回一个空的JSON结果(或做任何你喜欢的事情),因为用户没有登录。对于其他响应,你只需要像往常一样重定向用户。
更好的是,您可以覆盖OnAuthorization
类的AuthorizeAttribute
,这样您就不必重新发明轮子。添加上面提到的逻辑并在filterContext.Cancel
为真时拦截(filterContext.Result
将设置为HttpUnauthorizedResult
类的实例。
在Phil Haacks博客上阅读有关"Filters in ASP.NET MVC CodePlex Preview 4"的更多信息。它也适用于最新的预览。
答案 6 :(得分:1)
您可以在操作中调用此方法,
HttpContext.Response.End();
实施例
public async Task<JsonResult> Return401()
{
HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
HttpContext.Response.End();
return Json("Unauthorized", JsonRequestBehavior.AllowGet);
}
From MSDN:End方法使Web服务器停止处理脚本并返回当前结果。不处理文件的剩余内容。