【问题标题】:Set 403 error page in MVC在 MVC 中设置 403 错误页面
【发布时间】: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 的默认错误页面, 我在这里缺少什么,任何想法

【问题讨论】:

    标签: asp.net-mvc-3 c#-4.0 http-status-code-403 unauthorized


    【解决方案1】:

    除了 Max B 之外,只是一个小提示/注释。回答:

    当我使用自定义错误时,我会创建 ErrorsController 和 UnAuthorize ActionResult 并执行以下操作:

    <error statusCode="403" redirect="/Errors/UnAuthorize" />
    

    这样我可以在控制器中添加额外信息或执行其他操作,例如:

    • 就像有人试图访问经过身份验证的区域时登录到数据库一样。
    • 错误计数。
    • 可能是他们可以用来发送管理员信息的错误或报告表单。
    • ...

    这样您就可以更好地控制正在发生的事情。

    【讨论】:

    • 其实我也在做同样的事情,Shared 是控制器,Unauthorized 是动作,但我仍然收到相同的默认 http 403 页面错误,而不是我定义的页面
    • @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();
            }
        

        【讨论】:

          猜你喜欢
          • 2015-04-04
          • 1970-01-01
          • 2014-12-19
          • 2011-07-01
          • 1970-01-01
          • 2016-12-10
          • 2011-03-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多