如何在ASP.NET MVC中拦截来自Forms身份验证的401错误?

14

如果用户没有正确的权限,我想生成一个401页面。

当用户请求一个URL时,会被重定向到登录页面(我在web.config中禁止了所有匿名用户)。用户成功登录后,将被重定向回原始URL。然而,在权限检查时,确定用户没有所需的权限,因此我想生成一个401错误代码。但是Forms身份验证总是处理401并将用户重定向到登录页面。

对我来说,这不正确。用户已经进行了身份验证,只是没有正确的授权。

在其他场景中,比如ajax或REST服务场景,我绝对不希望出现登录页面 - 我需要正确的401页面。

到目前为止,我尝试过自定义授权筛选器以返回具有401状态码的ViewResult,但没有成功。然后,我尝试了正常的Action Filter,覆盖了OnActionExecuting,但也没有成功。

我能够做的是在global.asax中处理一个事件PostRequestHandlerExecute,检查权限,然后直接向响应写入内容:

if (permissionDenied)
{
    Context.Response.StatusCode = 401;
    Context.Response.Clear();
    Context.Response.Write("Permission Denied");
    Context.Response.Flush();
    Context.Response.Close();
    return;
}
那个方法可以工作,但并不是我想要的。 首先,我甚至不确定那是否是正确的事件或者管道中正确的位置来做这件事。 其次,我想让401页面有更多的内容。最好是一个aspx页面,可能与网站的其他页面拥有相同的母版页。这样,浏览网站的任何人都可以看到权限被拒绝,但具有相同的外观和感觉等等。但是Ajax或服务用户将获得适当的状态代码以采取行动。
有什么想法如何实现这个目标吗? 我看到了其他帖子有类似的请求,但没有看到我能使用的解决方案。
不,我不想要403。
4个回答

8
我找到了一个可行的解决方案。
EndRequest期间,FormsAuthenticationModule会发生401重定向。由于在事件处理期间模块是在global.asax之前被调用的,因此我们可以在FormsAuthenticationModule对请求进行处理后覆盖状态码。
在我的自定义AuthorizationFilter中,我将HttpContext.Items["PermissionDenied"]设置为true,然后在我的global.asax EndRequest中,我将状态码从200翻转为401。然后我使用Server.Transfer转到我的自定义PermissionDenied视图。
我仍然希望FormsAuthenticationModule本身能够更新以处理这种情况,但我认为这并不太过于hackish,我想我可以接受它。
显然,您可以更改如何表示global.asax应翻转状态码。我只是尝试将状态代码设置为511之类的内容,并将其用作条件,而不是使用HttpContext.Items,这也起作用。我想只要正确的状态码传出去,ASP.NET引擎就不会在意。

7
HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;

2

我同意默认行为是错误的,特别是在Ajax请求中。我希望在MVCv3中能够看到某种解决方案(手指交叉)。

我所知道的唯一实现方法是删除web.config中的身份验证部分,这是ASP.NET用于重定向未经授权的请求的部分。据我所知,您无法禁用此“功能”。如果您有身份验证部分,那么如果ASP.NET遇到401状态代码,您将被重定向到登录url。

但是通过删除此部分,您会遇到其他问题。如果您希望用户针对非Ajax请求重定向到登录页面,则需要实现自己的AuthorizeAttribute并使用自定义设置来确定要重定向到哪里。此外,身份验证部分中的任何其他内容也可能需要由您重新实现。在复杂的站点中,这不是一个非常实用的解决方案。

我自己没有这样做,我选择返回403。没有返回正确的HttpCode很烦人,但这比我迄今为止找到的任何其他解决方案都要好。


2
你说得对 - 我刚刚在FormsAuthenticationModule中使用了Reflector,在EndRequest处理程序中检查了401并进行了重定向。看起来没有办法覆盖这种行为。 - Jiho Han
是啊,403状态码现在听起来也不那么糟糕了 :) - Jab

0

我不确定你指向哪个答案。 无论如何,我不想重新路由或重定向,因为那样我的响应状态将不是401 - 它将是类似于302后跟200的东西,这不是我从ajax客户端访问url时所期望的。 - Jiho Han
Jiho - 对不起,我没有仔细阅读问题。我以为你只是想进行自定义的401重定向。 - Robaticus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接