在 MVC 中设置 403 错误页面
Posted
技术标签:
【中文标题】在 MVC 中设置 403 错误页面【英文标题】:Set 403 error page in MVC 【发布时间】:2011-10-24 17:36:31 【问题描述】:我重写了类来执行自定义授权
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
if (filterContext.HttpContext.Request.IsAuthenticated)
filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult(403);
else
base.HandleUnauthorizedRequest(filterContext);
现在在 web.config 中我已经配置了 403 错误页面
<customErrors defaultRedirect="/Shared/Error" mode="On">
<error statusCode="403" redirect="/Shared/UnAuthorize" />
</customErrors>
但浏览器仍然显示 403 的默认错误页面, 我在这里缺少什么,任何想法
【问题讨论】:
【参考方案1】:除了 Max B 之外,只是一个小提示/注释。回答:
当我使用自定义错误时,我会创建 ErrorsController
和 UnAuthorize ActionResult 并执行以下操作:
<error statusCode="403" redirect="/Errors/UnAuthorize" />
这样我可以在控制器中添加额外信息或执行其他操作,例如:
就像有人试图访问经过身份验证的区域时登录到数据库一样。 错误计数。 可能是他们可以用来发送管理员信息的错误或报告表单。 ...这样您就可以更好地控制正在发生的事情。
【讨论】:
其实我也在做同样的事情,Shared 是控制器,Unauthorized 是动作,但我仍然收到相同的默认 http 403 页面错误,而不是我定义的页面 非常有用的链接***.com/questions/2504923/… @SaboorAwan。我尝试了同样的方法,但没有运气。控制器方法永远不会被调用。您是否通过此答案或您发布的链接解决了问题?【参考方案2】:我知道这是一个非常古老的问题,但我正在为可能有同样问题的人发帖。像我一样,我有同样的问题并解决了它。如果你想在 web.config 中触发 customErrors 元素,你可以试试下面。
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
throw new HttpException(403, "Forbidden");
【讨论】:
比其他解决方案更完美、更轻松。 你把这个放在哪里?很高兴添加。可以是特定区域的吗? @RageCompex 您可以将它们放在您的自定义属性类中。您能否详细说明“特定区域”? 我的 50 美分,使用 System.Net.HttpStatusCode Enum 获取状态码。例如:(int)HttpStatusCode.Forbidden【参考方案3】:当我编写自己的自定义 AuthorizeAttribute 时,我遇到了与您完全相同的问题。当我在 web.config 中添加“customErrors”标签时,不会显示 403 的自定义错误页面。 我就是这样解决的:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
if (filterContext.HttpContext.Request.IsAuthenticated)
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(
new
controller = "Error",
action = "Unauthorised"
)
);
else
base.HandleUnauthorizedRequest(filterContext);
为filterContext.Result分配了一个我想显示的路由,而不是分配403 HttpStatusCode。
【讨论】:
【参考方案4】:或者你可以做这个替代解决方案,而不是使用:
filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult(403);
你可以把它改成:
if (filterContext.HttpContext.Request.IsAuthenticated)
throw new UnauthorizedAccessException();
并在您的 Controller/BaseController 中覆盖方法 OnException(ExceptionContext filterContext)
protected override void OnException(ExceptionContext filterContext)
if (filterContext.ExceptionHandled)
return;
if (filterContext.Exception.GetType() == typeof(UnauthorizedAccessException))
filterContext.Result = new ViewResult
ViewName = "~/Views/Error/NotAuthorized.cshtml"
;
filterContext.ExceptionHandled = true;
return;
base.OnException(filterContext);
【讨论】:
【参考方案5】:在我看来,HttpStatusCodeResult(403) 的 if 分支是错误的。在我看来,代码应该是这样的:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
if (!filterContext.HttpContext.Request.IsAuthenticated)
base.HandleUnauthorizedRequest(filterContext);
filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult(403);
【讨论】:
你可能想测试一下......它在验证时绕过了授权要求。【参考方案6】:mvc 中如何处理 401(未授权)、403(禁止)和 500(内部服务器错误)。用于 ajax/非 ajax 调用和 aspx 表单下的身份验证。
可以改变它以不同方式处理各种未捕获的异常,并且无论请求是否为 ajax,都可以做出不同的反应。 auth 部分允许它绕过任何常规的 mvc web 表单重定向到登录页面,而是返回 401 未授权 - 然后您的客户端 js 框架可以更轻松地对 http 状态 401/403 做出反应。
// FilterConfig.cs:
filters.Add(new ApplicationAuthorizeAttribute());
filters.Add(new ApplicationHandleErrorAttribute());
public class ApplicationAuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
// Note: To reach here, a Web.config path-specific rule 'allow users="?"' is needed (otherwise it redirects to login)
var httpContext = filterContext.HttpContext;
var request = httpContext.Request;
var response = httpContext.Response;
if (request.IsAjaxRequest())
response.SuppressFormsAuthenticationRedirect = true;
response.TrySkipIisCustomErrors = true;
filterContext.Result = new HttpUnauthorizedResult();
public class ApplicationHandleErrorAttribute : HandleErrorAttribute
public override void OnException(ExceptionContext context)
var exception = context.Exception is AggregateException
? ((AggregateException)context.Exception).InnerExceptions.First()
: context.Exception;
var request = context.HttpContext.Request;
var response = context.HttpContext.Response;
var isAjax = request.IsAjaxRequest();
if (exception is MyCustomPermissionDeniedException)
filterContext.Result = new HttpStatusCodeResult(HttpStatusCode.Forbidden);
response.TrySkipIisCustomErrors = isAjax;
filterContext.ExceptionHandled = true;
return;
#if DEBUG
if (!isAjax)
// Show default aspx yellow error page for developers
return;
#endif
var requestUri = request.Url == null ? "" : request.Url.AbsoluteUri;
MyCustomerLogger.Log(exception, requestUri);
response.Clear();
response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
#if DEBUG
var errorMessage = exception.Message;
#else
var errorMessage = "An error occurred, please try again or contact the administrator.";
#endif
response.Write(isAjax
? JsonConvert.SerializeObject(new Message = errorMessage)
: errorMessage);
response.End();
response.TrySkipIisCustomErrors = true;
context.ExceptionHandled = true;
Web.config:
<system.webServer>
<authentication mode="Forms">
<forms name=".MYAUTHCOOKIE" protection="All" loginUrl="/Account/Login" timeout="18000" slidingExpiration="true" enableCrossAppRedirects="false" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
</system.webServer>
<!-- ajax api security done via ApplicationAuthorizeAttribute -->
<location path="api">
<system.web>
<authorization>
<allow users="?"/>
</authorization>
</system.web>
</location>
Web 服务 api 请求的附加路由:(放在常规 mvc 路由之上)
// This route has special ajax authentication handling (no redirect to login page)
routes.MapRoute(
name: "DefaultApi",
url: "api/controller/action/id",
defaults: new id = UrlParameter.Optional
);
jquery 处理错误的示例客户端代码:
$.ajaxSetup(
complete: function onRequestCompleted(xhr, textStatus)
if (xhr.readyState == 4 && xhr.status == 401)
// Not needed with smart status: && xhr.responseText.substring(0, 150).indexOf("<title>Log in") != -1
//location.href = "/Account/Login";
alert("Your session has timed out.");
);
或者,您可以让所有身份验证都通过 ApplicationHandleErrorAttribute,并摆脱 web.config 拒绝用户 =“?”。但是我有一个遗留的 aspx 页面,它没有命中 mvc 过滤,所以我想要拒绝用户 =“?”。
【讨论】:
您实际上应该可以 F12(resharper 反编译?ms 符号服务器?)进入:ControllerActionInvoker、HandleErrorAttribute、AuthorizeAttribute。这是非常有启发性的阅读。 ControllerActionInvoker 以不同的方式使用 4 种过滤器类型中的每一种。 (身份验证、操作、结果、异常)例如转到您的控制器,在基类“Controller”上按 F12,在“IAuthorizationFilter”上按 F12,在“OnAuthorization”上按 Shift-F12。【参考方案7】:1-创建一个名为LoggedOrAuthorizedAttribute
的类
public class LoggedOrAuthorizedAttribute: AuthorizeAttribute
public override void OnAuthorization(AuthorizationContext filterContext)
base.OnAuthorization(filterContext);
CheckIfUserIsAuthenticated(filterContext);
private void CheckIfUserIsAuthenticated(AuthorizationContext filterContext)
// If Result is null, we're OK: the user is authenticated and authorized.
if (filterContext.Result == null)
return;
// If here, you're getting an HTTP 401 status code. In particular,
// filterContext.Result is of HttpUnauthorizedResult type. Check Ajax here.
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
filterContext.Result = new RedirectResult("/Error/Error401");
2-将您创建的属性添加到操作的顶部
[LoggedOrAuthorizedAttribute(Roles = "Admin")]
public ActionResult Index()
return View();
[LoggedOrAuthorizedAttribute(Roles = "User")]
public ActionResult IndexUser()
return View();
【讨论】:
以上是关于在 MVC 中设置 403 错误页面的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 mvc 项目重定向到默认的 403 错误页面,而不是我重定向到的页面,而不是在本地的 IIS 上?
前端使用 ajax 访问后端 django 程序 报错误: POST http://127.0.0.1:8001/xxx 403 (Forbidden)