C# 使用AuthorizeAttribute会使ErrorsController无法访问

C# 使用AuthorizeAttribute会使ErrorsController无法访问,c#,asp.net-mvc,attributes,C#,Asp.net Mvc,Attributes,我读了一篇关于使用全局过滤器进行“白名单”认证实践的文章,并决定尝试一下 症状: 我做了一个快速测试&控制器的操作被正确地拒绝,但是 异常不再在Global.ASAX的“Application_Error”中出现…因此它无法(再)重定向 ErrorsController操作不再触发…因此用户永远不会重定向到自定义错误 注释掉下面的WEB.CONFIG条目只会导致页面显示“错误404.15-未找到” 结果是404找不到…这是有道理的。但是,重定向失败。因此,浏览器只显示一个空的、未设置样式的页

我读了一篇关于使用全局过滤器进行“白名单”认证实践的文章,并决定尝试一下

症状:
我做了一个快速测试&控制器的操作被正确地拒绝,但是

  • 异常不再在Global.ASAX的“Application_Error”中出现…因此它无法(再)重定向
  • ErrorsController操作不再触发…因此用户永远不会重定向到自定义错误
  • 注释掉下面的WEB.CONFIG条目只会导致页面显示“错误404.15-未找到”
结果是404找不到…这是有道理的。但是,重定向失败。因此,浏览器只显示一个空的、未设置样式的页面。显然,用户永远不会知道它是404找不到的,除非他们足够精明,能够在控制台中查看……这很糟糕

更新:
所有这些代码都在这些更改之前工作。添加过滤器会导致这些症状

以下是我为进行测试所做的更改……我是否遗漏了什么?

我的测试代码如下所示:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();
    GlobalConfiguration.Configure(WebApiConfig.Register);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

protected void Application_Error(object sender, EventArgs e)
{
    HttpContext httpContext = ((MvcApplication)sender).Context;
    Exception unhandledException = Server.GetLastError();
    HttpException httpException = GetHttpException(unhandledException);

    if (httpException != null)
    {
        int httpCode = httpException.GetHttpCode();
        switch (httpCode)
        {
            // These should redirect automatically.
            case (int)HttpStatusCode.Forbidden:
            case (int)HttpStatusCode.NotFound:
            case (int)HttpStatusCode.Unauthorized:
                return;
            default:
                httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                return;
        }
    }
}

public class FilterConfig
{
    #region <Methods>

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        // FORCE: Authorize on all actions (by default)
        filters.Add(new AuthorizeAttribute());
    }

    #endregion
}

// The AUTHORIZE ATTRIBUTE is now defaulted on all actions...so we don't need it here
public class AccountController : BaseController
{
    #region <Actions>

    [HttpGet]
    // The TEST is to see the ERRORS PAGE COME UP so put nothing here
    public ActionResult Login(string returnUrl)
    {
        // The user-call should be redirected to the error page when called...but oddly isn't
    }

    #endregion
}

[AllowAnonymous]
public class ErrorsController : Controller
{
    #region <Actions>

    // GET: /Errors/Unexpected
    [HttpGet]
    [AllowAnonymous]
    public ActionResult Unexpected()
    {
        TraceHandler.TraceIn(TraceLevel.Error);

        var unitOfWork = new ApplicationUnitOfWork();
        var viewModel = new UnExpectedErrorViewModel(unitOfWork);

        Response.StatusCode = (int)viewModel.StatusCode;
        Response.TrySkipIisCustomErrors = true;

        TraceHandler.TraceOut();
        return View(viewModel);
    }

    // GET: /Errors/Forbidden
    [HttpGet]
    [AllowAnonymous]
    public ActionResult Forbidden()
    {
        TraceHandler.TraceIn(TraceLevel.Error);

        var unitOfWork = new ApplicationUnitOfWork();
        var viewModel = new ForbiddenErrorViewModel(unitOfWork);

        Response.StatusCode = (int)viewModel.StatusCode;
        Response.TrySkipIisCustomErrors = true;
        Response.SuppressFormsAuthenticationRedirect = true;

        TraceHandler.TraceOut();
        return View(viewModel);
    }

    // GET: /Errors/NotFound
    [HttpGet]
    [AllowAnonymous]
    public ActionResult NotFound()
    {
        TraceHandler.TraceIn(TraceLevel.Error);

        var unitOfWork = new ApplicationUnitOfWork();
        var viewModel = new NotFoundErrorViewModel(unitOfWork);

        Response.StatusCode = (int)viewModel.StatusCode;
        Response.TrySkipIisCustomErrors = true;

        TraceHandler.TraceOut();
        return View(viewModel);
    }

    #endregion
}
受保护的无效应用程序\u Start()
{
RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
受保护的无效应用程序\u错误(对象发送方,事件参数e)
{
HttpContext HttpContext=((mvcapApplication)发送方).Context;
Exception unhandledException=Server.GetLastError();
HttpException HttpException=GetHttpException(未处理的异常);
if(httpException!=null)
{
int httpCode=httpException.GetHttpCode();
交换机(httpCode)
{
//这些应该自动重定向。
案例(int)HttpStatusCode.Forbidden:
案例(int)HttpStatusCode.NotFound:
案例(int)HttpStatusCode.Unauthorized:
返回;
违约:
httpContext.Response.StatusCode=(int)HttpStatusCode.InternalServerError;
返回;
}
}
}
公共类筛选器配置
{
#区域
公共静态无效注册表全局过滤器(全局过滤器集合过滤器)
{
//强制:对所有操作进行授权(默认情况下)
filters.Add(新的AuthorizeAttribute());
}
#端区
}
//AUTHORIZE属性现在在所有操作上都是默认的…所以这里不需要它
公共类AccountController:BaseController
{
#区域
[HttpGet]
//测试是看到错误页面出现,所以这里什么也不放
公共操作结果登录(字符串返回URL)
{
//调用时,用户调用应该重定向到错误页面…但奇怪的是,不是这样
}
#端区
}
[异名]
公共类错误控制器:控制器
{
#区域
//获取:/Errors/意外
[HttpGet]
[异名]
公共操作结果意外()
{
TraceHandler.TraceIn(TraceLevel.Error);
var unitOfWork=新应用程序unitOfWork();
var viewModel=新的意外错误视图模型(unitOfWork);
Response.StatusCode=(int)viewModel.StatusCode;
Response.tryskipiiscustomerors=true;
TraceHandler.TraceOut();
返回视图(viewModel);
}
//获取:/Errors/禁止
[HttpGet]
[异名]
公共行动结果禁止()
{
TraceHandler.TraceIn(TraceLevel.Error);
var unitOfWork=新应用程序unitOfWork();
var viewModel=新的禁止错误viewModel(unitOfWork);
Response.StatusCode=(int)viewModel.StatusCode;
Response.tryskipiiscustomerors=true;
Response.SuppressFormsAuthenticationRedirect=true;
TraceHandler.TraceOut();
返回视图(viewModel);
}
//获取:/Errors/NotFound
[HttpGet]
[异名]
公共行动结果未找到()
{
TraceHandler.TraceIn(TraceLevel.Error);
var unitOfWork=新应用程序unitOfWork();
var viewModel=新的NotFoundErrorViewModel(unitOfWork);
Response.StatusCode=(int)viewModel.StatusCode;
Response.tryskipiiscustomerors=true;
TraceHandler.TraceOut();
返回视图(viewModel);
}
#端区
}
WEB配置如下所示:
当然,所有这些之前都连接在web.config中以正确运行。事实上,这确实在测试条件之前运行

<!-- CUSTOM ERRORS: httpErrors -->
    <httpErrors existingResponse="Replace" errorMode="Custom">
      <remove statusCode="403" subStatusCode="-1" />
      <error statusCode="403" prefixLanguageFilePath="" path="/yourapplication/errors/forbidden" responseMode="ExecuteURL" />
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" prefixLanguageFilePath="" path="/yourapplication/errors/notfound" responseMode="ExecuteURL" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="500" prefixLanguageFilePath="" path="/yourapplication/errors/unexpected" responseMode="ExecuteURL" />
    </httpErrors>

[AllowAnonymous]
属性注释您的
ErrorController
。基本上,通过将全局筛选器注册为:

// FORCE: Authorize on all actions (by default)
filters.Add(new AuthorizeAttribute());
您正在强制用户在登录时查看错误。如果仍要执行此操作,则必须从该筛选器中跳过
ErrorController
(这是
AllowAnonymousAttribute
为您做的。)

现在回到web.config,您不需要在那里添加该部分。您可以在“应用程序错误”方法中处理状态代码,如下所示:

        protected void Application_Error()
        {
            var exception = Server.GetLastError();
            var httpException = exception as HttpException;
            Response.Clear();
            Server.ClearError();
            var routeData = new RouteData();
            routeData.Values["controller"] = "Error";
            routeData.Values["action"] = "General";
            routeData.Values["exception"] = exception;
            Response.StatusCode = 500;
            if (httpException != null)
            {
                Response.StatusCode = httpException.GetHttpCode();
                switch (Response.StatusCode)
                {
                    case 403:
                        routeData.Values["action"] = "Forbidden";
                        break;

                    case 404:
                        routeData.Values["action"] = "NotFound";
                        break;

                   case 500:
                        routeData.Values["action"] = "UnExpected";
                        break;
                }
            }

            IController errorsController = new ErrorController();
            var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
            errorsController.Execute(rc);
        }
你可能会得到404,因为你的路径似乎是错误的。
您的应用程序在这些路径中做什么

<httpErrors existingResponse="Replace" errorMode="Custom">
      <remove statusCode="403" subStatusCode="-1" />
      <error statusCode="403" prefixLanguageFilePath="" path="/errors/forbidden" responseMode="ExecuteURL" />
      <remove statusCode="404" subStatusCode="-1" />
      <error statusCode="404" prefixLanguageFilePath="" path="/errors/notfound" responseMode="ExecuteURL" />
      <remove statusCode="500" subStatusCode="-1" />
      <error statusCode="500" prefixLanguageFilePath="" path="/errors/unexpected" responseMode="ExecuteURL" />
    </httpErrors>

[AllowAnonymous]
属性注释您的
ErrorController
。基本上,通过将全局筛选器注册为:

// FORCE: Authorize on all actions (by default)
filters.Add(new AuthorizeAttribute());
您正在强制用户在登录时查看错误。如果仍要执行此操作,则必须从该筛选器中跳过
ErrorController
(这是
AllowAnonymousAttribute
为您做的。)

现在回到web.config,您不需要在那里添加该部分。您可以在“应用程序错误”方法中处理状态代码,如下所示:

        protected void Application_Error()
        {
            var exception = Server.GetLastError();
            var httpException = exception as HttpException;
            Response.Clear();
            Server.ClearError();
            var routeData = new RouteData();
            routeData.Values["controller"] = "Error";
            routeData.Values["action"] = "General";
            routeData.Values["exception"] = exception;
            Response.StatusCode = 500;
            if (httpException != null)
            {
                Response.StatusCode = httpException.GetHttpCode();
                switch (Response.StatusCode)
                {
                    case 403:
                        routeData.Values["action"] = "Forbidden";
                        break;

                    case 404:
                        routeData.Values["action"] = "NotFound";
                        break;

                   case 500:
                        routeData.Values["action"] = "UnExpected";
                        break;
                }
            }

            IController errorsController = new ErrorController();
            var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
            errorsController.Execute(rc);
        }
你大概有40岁了