使用AuthorizeAttribute使ErrorsController不可访问

本文关键字:访问 ErrorsController AuthorizeAttribute 使用 | 更新日期: 2023-09-27 18:10:22

我读过一篇关于使用全局过滤器将所有MVC控制器动作默认为"白名单"认证实践的文章& &;决定试一试。

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

  • 异常不再在全局引发。ASAX"Application_Error"……所以它不能(再)重定向。
  • ErrorsController动作不再触发…所以用户永远不会被重定向到自定义错误
  • 注释掉WEB。下面的配置项只会导致页面显示"错误404.15 -未找到"

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

更新:
在这些更改之前,所有这些代码都可以正常工作。添加FILTER会导致这些症状。

下面是我为进行测试所做的更改…我错过什么了吗?

我的测试代码看起来像:

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配置如下:
当然,这一切之前都是通过网络实现的。配置以正确运行。而且,实际上,这确实在测试条件之前运行。

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

使用AuthorizeAttribute使ErrorsController不可访问

在web配置中使用System.Web下的customErrors元素代替httpErrors:

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

这里Error是控制器名称,Index是动作

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

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

你强迫你的用户在登录时看到错误。如果你仍然想这样做,那么你必须从这个过滤器中跳过你的ErrorController (AllowAnonymousAttribute为你做)

现在回到你的网页。配置,你不需要添加那个部分。你可以在你的'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>