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-未找到”
所有这些代码都在这些更改之前工作。添加过滤器会导致这些症状 以下是我为进行测试所做的更改……我是否遗漏了什么? 我的测试代码如下所示:
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岁了