Установите страницу ошибки 403 в MVC

Я переопределяю класс для выполнения пользовательской авторизации

[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, чего мне здесь не хватает, любая идея


person Saboor Awan    schedule 11.08.2011    source источник


Ответы (7)


Просто небольшой намек / примечание, кроме ответа Макса Б.:

Когда я использую пользовательские ошибки, я делаю ErrorsController и UnAuthorize ActionResult и делаю следующее:

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

Таким образом, я могу добавить дополнительную информацию или выполнить другие действия в моем контроллере, например:

  • Например, запись в базу данных о том, что кто-то пытался получить доступ к аутентифицированной области.
  • Ошибка подсчета.
  • Может быть, ошибка или форма отчета, которую они могут использовать для отправки информации администратору.
  • ...

Таким образом, у вас будет больше контроля над происходящим.

person Kevin Cloet    schedule 11.08.2011
comment
на самом деле я делаю то же самое, Shared - это контроллер, а Unauthorized - это действие, но все же я получаю ту же ошибку страницы http 403 по умолчанию, а не мою определенную страницу - person Saboor Awan; 11.08.2011
comment
очень полезная ссылка stackoverflow.com/questions/2504923/ - person Saboor Awan; 16.08.2011
comment
@СабурАван. Я пробовал то же самое без везения. Метод контроллера никогда не вызывается. Вы решаете проблему с помощью этого ответа или ссылки, которую вы разместили? - person Marco; 19.12.2012

Я знаю, что это очень старый вопрос, но я пишу для тех, у кого может быть такая же проблема. Как и у меня, у меня была такая же проблема, и я решил ее. Если вы хотите активировать элемент customErrors в web.config, вы можете попробовать ниже.

protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
    throw new HttpException(403, "Forbidden");
}
person genki98    schedule 25.06.2014
comment
Работает отлично и проще, чем другие решения. - person Guillaume; 07.01.2015
comment
где ты это ставишь? Хорошо бы добавить. Может ли это быть конкретным регионом? - person CularBytes; 05.02.2016
comment
@RageCompex Вы можете поместить их в свой собственный класс атрибутов. И не могли бы вы подробнее рассказать о «специфике области»? - person genki98; 16.02.2016
comment
Мои 50 центов, используйте System.Net.HttpStatusCode Enum, чтобы получить коды состояния. Например: (int)HttpStatusCode.Forbidden - person Renan Araújo; 01.08.2018

У меня была та же проблема, что и у вас, когда я написал свой собственный AuthorizeAttribute. Пользовательская страница ошибок для 403 не будет отображаться, когда я добавлю тег «customErrors» в 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 RedirectToRouteResult(
                new RouteValueDictionary(
                    new
                        { 
                            controller = "Error", 
                            action = "Unauthorised" 
                        })
                ); 

        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

Назначил маршрут, который хотел бы отобразить, в filterContext.Result вместо назначения 403 HttpStatusCode.

person Amna Ali    schedule 31.12.2013

Или вы можете сделать это альтернативное решение вместо использования:

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

вы можете изменить его на:

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

И переопределите метод 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);
    }
person Rivera    schedule 08.12.2011

Мне кажется, что 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);
        }
    }
}
person hydr    schedule 11.08.2011
comment
Возможно, вы захотите проверить это... он обходит требование авторизации при проверке подлинности. - person JustinStolle; 12.04.2012

Как обрабатывать 401 (несанкционированный доступ), 403 (запрещено) и 500 (внутренняя ошибка сервера) в mvc. Для вызовов ajax/не-ajax и проверки подлинности форм aspx.

Его можно изменить, чтобы по-разному обрабатывать различные необработанные исключения и реагировать по-разному, независимо от того, является ли запрос ajax или нет. Часть аутентификации позволяет ему обходить любые обычные веб-формы mvc, перенаправляющие на страницу входа, и вместо этого возвращать 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>

Дополнительный маршрут для запросов 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 deny users="?". Но у меня есть устаревшая страница aspx, которая не попадает в фильтрацию mvc, поэтому я хочу запретить пользователям = "?".

person Curtis Yallop    schedule 27.05.2015
comment
На самом деле вы должны иметь возможность использовать F12 (перекомпилировать? Сервер символов ms?) в: ControllerActionInvoker, HandleErrorAttribute, AuthorizeAttribute. Это очень поучительное чтение. ControllerActionInvoker по-разному использует каждый из 4 типов фильтров. (авторизация, действие, результат, исключение) Например, перейдите к своему контроллеру, нажмите F12 на контроллере базового класса, F12 на IAuthorizationFilter, Shift-F12 на OnAuthorization. - person Curtis Yallop; 27.05.2015

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();
    }
person Diako Hasani    schedule 17.06.2021