使用AuthorizeAttribute使ErrorsController无法访问

时间:2015-08-30 15:03:35

标签: c# asp.net-mvc attributes

我读了一篇关于使用全局过滤器default all MVC Controller Actions到白名单'认证实践&决定尝试一下。

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

  • 在Global.ASAX" Application_Error" ...中不再引发异常,因此无法重定向(再)。
  • ErrorsController操作不再触发......因此用户永远不会被重定向到自定义错误
  • 评论下面的WEB.CONFIG条目只会导致页面显示"错误404.15 - 未找到"

结果是404 NOT FOUND ......这是有道理的。但是,重定向失败。结果,浏览器只显示一个空的,没有样式的页面。显然,用户永远不会知道它是 404 NOT FOUND ,除非他们足够聪明地查看控制台......这很糟糕。

更新
所有这些代码在这些更改之前都有效。添加FILTER会导致这些症状。

以下是我为进行测试所做的更改...我错过了什么?

MY TEST-CODE看起来像:

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
}

WEB CONFIG看起来像:
当然,以前所有这些都是在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>

2 个答案:

答案 0 :(得分:0)

使用ErrorController属性为[AllowAnonymous]添加注释。基本上,通过将全局过滤器注册为:

// FORCE: Authorize on all actions (by default)
filters.Add(new AuthorizeAttribute());

您强制用户在登录时看到错误。如果您仍想这样做,则必须跳过此ErrorController此过滤器(AllowAnonymousAttribute为您执行此操作。 )

现在回到你的web.config,你不需要在那里添加那个部分。您可以在“Application_Error”方法中处理状态代码,如下所示:

        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,因为你的路径似乎是错误的。 yourapplication在这些路径上做了什么?

<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>

答案 1 :(得分:0)

而不是httpErrors在网络配置中的customErrors下使用System.Web元素:

 <system.web>

    <customErrors mode="On">
            <error statusCode="500"
                   redirect="~/Error/Index" />
            <error statusCode="404"
                   redirect="~/Error/Index" />
        </customErrors>
</system.web>

此处错误是控制器名称,索引是操作。