在MVC中设置403错误页面

发布于 2024-11-29 01:13:13 字数 861 浏览 1 评论 0原文

我现在在 web.config 中重写该类以执行自定义授权

[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);
        }
    }
}

,我已经配置了 403 错误页面

<customErrors defaultRedirect="/Shared/Error" mode="On">
  <error statusCode="403" redirect="/Shared/UnAuthorize" />
</customErrors>

,但浏览器仍然显示 403 的默认错误页面, 我在这里缺少什么,任何想法

I overrides the class to perform custom Authorization

[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);
        }
    }
}

now in web.config i have configured the 403 error page

<customErrors defaultRedirect="/Shared/Error" mode="On">
  <error statusCode="403" redirect="/Shared/UnAuthorize" />
</customErrors>

but the browser still shows me default error page for 403,
what i am missing here, any idea

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

拧巴小姐 2024-12-06 01:13:13

我知道这是一个非常老的问题,但我是为可能有同样问题的人发帖。像我一样,我也遇到了同样的问题并解决了。如果你想触发web.config中的customErrors元素,你可以尝试下面的方法。

protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
    throw new HttpException(403, "Forbidden");
}

I know this is very old question, but I'm posting for someone who might have same issue. Like me, I had same issue and solved it. If you want to trigger the customErrors element in web.config, you can try below.

protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
    throw new HttpException(403, "Forbidden");
}
后eg是否自 2024-12-06 01:13:13

除了 Max B 之外,还有一个小提示/注释:

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

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

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

  • 例如记录到有人尝试访问经过身份验证的区域的数据库。
  • 计数错误。
  • 也许是他们可以用来发送管理信息的错误或报告表格。
  • ...

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

Just a small hint/note besides Max B. answer:

When I'm using custom errors I make an ErrorsController, and a UnAuthorize ActionResult and do the following:

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

This way I can add extra information or do other actions in my controller, for example:

  • Like logging to the database that someone tried to access an authenticated area.
  • Error counting.
  • Maybe a bug or report form that they can use to send the admin information.
  • ...

This way you have some more control on what's happening.

一身仙ぐ女味 2024-12-06 01:13:13

当我编写自己的自定义 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。

I had the exact same issue as you had when i wrote my own custom AuthorizeAttribute. The custom errors page for 403 won't show up when I added "customErrors" tag in web.config.
This is how I got it resolved:

[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);
        }
    }
}

Assigned a route that I would like to display to filterContext.Result, instead of assigning 403 HttpStatusCode.

当梦初醒 2024-12-06 01:13:13

或者您可以执行此替代解决方案,而不是使用:

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);
    }

Or you can do this alternative solution,instead of using :

filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult(403);

you can change it to :

if (filterContext.HttpContext.Request.IsAuthenticated)
        {               
            throw new UnauthorizedAccessException();
        }

And override method OnException(ExceptionContext filterContext) in your Controller/BaseController

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);
    }
但可醉心 2024-12-06 01:13:13

对我来说, 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);
        }
    }
}

To me it seems that the the HttpStatusCodeResult(403) is in the wrong if branch. In my opinion the code should look like this:

[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);
        }
    }
}
祁梦 2024-12-06 01:13:13

如何在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 过滤,所以我希望拒绝 users="?"。

How to handle 401 (Unauthorized), 403 (Forbidden) and 500 (Internal Server Error) in mvc. For ajax/non-ajax calls and under aspx forms authentication.

It can be altered to handle various uncaught exceptions differently and react differently whether the request is ajax or not. The auth part allows it to bypass any regular mvc web forms redirect-to-login-page and instead return 401 unauthorized - then your client-side js framework can react to http status 401/403 more easily.

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

Additional route for web service api requests: (put above regular mvc route)

// 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 }
);

Sample client side code for jquery to handle the error:

$.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.");
        }
    }
});

Alternatively, you could make all auth go through ApplicationHandleErrorAttribute, and get rid of that web.config deny users="?". But I have a legacy aspx page which doesn't hit the mvc filtering so I want that deny users="?".

猫瑾少女 2024-12-06 01:13:13

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();
    }

1-create a class call 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-Add the attribute you created to the top of your actions

    [LoggedOrAuthorizedAttribute(Roles = "Admin")]
    public ActionResult Index()
    {
        return View();
    }

    [LoggedOrAuthorizedAttribute(Roles = "User")]
    public ActionResult IndexUser()
    {
        return View();
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文