Подтвердить что ты не робот

Ошибка ASP.NET MVC 401

Я реализовал обработку ошибок в ASP.NET MVC-сайте таким образом, как предлагает этот пост.

С 404 ошибками все работает нормально. Но как правильно показать удобный экран для 401 ошибки? Обычно они не выбрасывают исключение, которое можно обрабатывать внутри Application_Error(), но скорее действие возвращает HttpUnauthorizedResult. Один из возможных способов - добавить следующий код в конец метода Application_EndRequest()

if (Context.Response.StatusCode == 401)
{
    throw new HttpException(401, "You are not authorised");
    // or UserFriendlyErrorRedirect(new HttpException(401, "You are not authorised")), witout exception
}

Но внутри Application_EndRequest() Context.Session == null, errorController.Execute() терпит неудачу, потому что он не может использовать стандартный TempDataProvider.

  // Call target Controller and pass the routeData.
  IController errorController = new ErrorController();
  errorController.Execute(new RequestContext(    
       new HttpContextWrapper(Context), routeData)); // Additional information: The SessionStateTempDataProvider requires SessionState to be enabled.

Итак, можете ли вы предложить несколько рекомендаций по использованию "удобного для пользователя дескриптора" 401 в приложении ASP.NET MVC?

Спасибо.

4b9b3361

Ответ 1

Посмотрите на HandleErrorAttribute. Подкласс от него или добавьте свою собственную реализацию, которая будет обрабатывать все интересующие вас коды состояния. Вы можете сделать это, чтобы вернуть отдельное представление ошибки для каждого типа ошибки.

Вот идея создания фильтра исключения ошибок обработки. Я выбросил большую часть материала, чтобы сосредоточиться только на наших основах. Абсолютно взгляните на исходную реализацию, чтобы добавить проверки аргументов и другие важные вещи.

public class HandleManyErrorsAttribute : FilterAttribute, IExceptionFilter
{
    public virtual void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
            return;

        Exception exception = filterContext.Exception;

        string viewName = string.Empty;
        object viewModel = null;
        int httpCode = new HttpException(null, exception).GetHttpCode();
        if (httpCode == 500)
        {
            viewName = "Error500View";
            viewModel = new Error500Model();
        }
        else if (httpCode == 404)
        {
            viewName = "Error404View";
            viewModel = new Error404Model();
        }
        else if (httpCode == 401)
        {
            viewName = "Error401View";
            viewModel = new Error401Model();
        }

        string controllerName = (string)filterContext.RouteData.Values["controller"];
        string actionName = (string)filterContext.RouteData.Values["action"];
        filterContext.Result = new ViewResult
        {
            ViewName = viewName,
            MasterName = Master,
            ViewData = viewModel,
            TempData = filterContext.Controller.TempData
        };
        filterContext.ExceptionHandled = true;
        filterContext.HttpContext.Response.Clear();
        filterContext.HttpContext.Response.StatusCode = httpCode;

        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    }
}

Затем вы "украшаете" свои действия с помощью этого атрибута:

[HandleManyErrors]
public ActionResult DoSomethingBuggy ()
{
    // ...
}

Ответ 2

Мне удалось решить это очень простым способом. Я хотел показать пользовательскую страницу для зарегистрированных пользователей ( "у вас нет разрешения bla bla..." ) и перенаправить неавторизованных пользователей на страницу входа (поведение по умолчанию). Поэтому я применил специальный атрибут AuthorizeAttribute (скажем, CustomAuthorizeAttribute) с методом HandleUnauthorizedRequest, который был перезаписан таким образом, что если пользователь аутентифицирован, я устанавливаю свойство Result аргумента filterContext с помощью ViewResult (в общей папке) под названием AccessDenied.aspx

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
    {
        base.HandleUnauthorizedRequest(filterContext);
    }
    else
    {
        filterContext.Result = new ViewResult { ViewName = "AccessDenied" };
    }
}

Затем вы должны использовать этот новый атрибут. С наилучшими пожеланиями.

Ответ 3

Если вы используете ASP.NET MVC, вы, скорее всего, будете использовать IIS, поэтому почему бы вам просто не настроить IIS для использования вашей страницы ошибок 401 для этого веб-приложения/виртуального каталога?

Ответ 4

В одном из моих проектов я использую код uvita.

У меня ASP.NET MVC2, и я использую аутентификацию Active Directory без страницы входа. У меня есть страница NoAuth.aspx, которая использует главную страницу сайта, интегрирует макет веб-приложения.

Это web.config.

<system.web>
    <authentication mode="Windows" />
    <roleManager enabled="true" defaultProvider="AspNetWindowsTokenRoleProvider">
       <providers>
          <clear />
          <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider"
          applicationName="/" />
      </providers>
    </roleManager>
</system.web>

Новый класс CustomAutorizeAttribute

using System.Web.Mvc;
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
        else
        {
           filterContext.Result = new ViewResult { ViewName = "NoAuth"};
        }
    }
}

и контроллер

[CustomAuthorize(Roles = "ADRole")]
public class HomeController : Controller
{
    public HomeController()
    {
    }
}