web-dev-qa-db-fra.com

Page d'erreur personnalisée ASP.NET MVC 5

J'utilise un attribut d'autorisation personnalisé dans une application ASP.NET MVC 5 comme suit:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext context)
    {
        if (context.HttpContext.Request.IsAuthenticated)
        {
            context.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);                
        }
        else
        {
            base.HandleUnauthorizedRequest(context);
        }
    }
}

Dans system.web section de mon web.config J'ai mentionné des chemins d'erreur comme:

<system.web>
    <customErrors mode="On" defaultRedirect="/Error/Error">
      <error statusCode="403" redirect="/Error/NoPermissions"/>
    </customErrors>
</system.web>

Mais je ne suis jamais redirigé vers ma page d'erreur personnalisée à /Error/NoPermissions. Au lieu de cela, le navigateur affiche la page d'erreur générale indiquant "Erreur HTTP 403.0 - Interdit".

29
Haider

Merci à tous, mais le problème n'est pas avec le code 403. En fait, le problème était avec la façon dont j'essayais de retourner 403. Je viens de changer mon code pour lancer un HttpException au lieu de retourner le HttpStatusCodeResult et tout fonctionne maintenant. Je peux retourner n'importe quel code d'état HTTP en lançant une exception HttpException et ma configuration customErrors les capture tous. Peut-être que HttpStatusCodeResult ne fait pas exactement le travail que j'attendais.

Je viens de remplacer

context.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);

avec

throw new HttpException((int)System.Net.HttpStatusCode.Forbidden, "Forbidden");

C'est ça.

Codage heureux.

18
Haider

[1]: Supprimez tous les 'customErrors' et 'httpErrors' de Web.config

[2]: Vérifiez que 'App_Start/FilterConfig.cs' ressemble à ceci:

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }
}

[3]: dans 'Global.asax' ajoutez cette méthode:

public void Application_Error(Object sender, EventArgs e)
{
    Exception exception = Server.GetLastError();
    Server.ClearError();

    var routeData = new RouteData();
    routeData.Values.Add("controller", "ErrorPage");
    routeData.Values.Add("action", "Error");
    routeData.Values.Add("exception", exception);

    if (exception.GetType() == typeof(HttpException))
    {
        routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
    }
    else
    {
        routeData.Values.Add("statusCode", 500);
    }

    Response.TrySkipIisCustomErrors = true;
    IController controller = new ErrorPageController();
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
    Response.End();
}

[4]: Ajoutez 'Controllers/ErrorPageController.cs'

public class ErrorPageController : Controller
{
    public ActionResult Error(int statusCode, Exception exception)
    {
         Response.StatusCode = statusCode;
         ViewBag.StatusCode = statusCode + " Error";
         return View();
    }
}

[5]: dans 'Vues/Partagé/Erreur.cshtml'

@model System.Web.Mvc.HandleErrorInfo
@{
    ViewBag.Title = (!String.IsNullOrEmpty(ViewBag.StatusCode)) ? ViewBag.StatusCode : "500 Error";
}

<h1 class="error">@(!String.IsNullOrEmpty(ViewBag.StatusCode) ? ViewBag.StatusCode : "500 Error"):</h1>

//@Model.ActionName
//@Model.ControllerName
//@Model.Exception.Message
//@Model.Exception.StackTrace

:RÉ

44
ubik404

J'ai également eu ce problème. Le code dans la question de l'OP fonctionne parfaitement, sauf le code d'erreur personnalisé dans <system.web> section dans le web.config fichier. Pour résoudre le problème, je devais ajouter le code suivant à <system.webServer>. Notez que ‘webserver’ au lieu de ‘web’.

<httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="403" />
  <error statusCode="403" responseMode="ExecuteURL" path="/Error/UnAuthorized" />
</httpErrors>

Si quelqu'un utilise l'environnement suivant, voici la solution complète:

L'environnement:

  • Visual Studio 2013 Update 4
  • Microsoft .NET Framework 4.5.1 avec ASP.NET MVC 5
  • Projet: Application Web ASP.NET avec MVC et authentification: modèle de compte d'utilisateur individuel

Classe d'attribut personnalisé:

Ajoutez la classe suivante à l'espace de noms par défaut de votre site Web. La raison expliquée ici dans la réponse acceptée Stack Overflow question:Pourquoi AuthorizeAttribute redirige-t-il vers la page de connexion pour les échecs d'authentification et d'autorisation?

[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((int)System.Net.HttpStatusCode.Forbidden);

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

Ajoutez ensuite le code suivant web.config fichier

<system.webServer>
   <httpErrors errorMode="Custom" existingResponse="Replace">
      <remove statusCode="403" />
      <error statusCode="403" responseMode="ExecuteURL" path="/Error/UnAuthorized" />
   </httpErrors>
</system.webServer>

L'article suivant explique en savoir plus: ASP.NET MVC: amélioration de l'attribut d'autorisation (403 interdit)

Et httpErrors dans web.config section de cet article: Démystification des pages d'erreur et de la journalisation des erreurs ASP.NET MVC 5

Ajoutez ensuite le ErrorController.cs au dossier Contrôleurs

public class ErrorController : Controller
{
    // GET: UnAuthorized
    public ActionResult UnAuthorized()
    {
        return View();
    }

    public ActionResult Error()
    {
        return View();
    }

}

Ajoutez ensuite un UnAuthorized.cshtml au dossier View/Shared

@{
    ViewBag.Title = "Your Request Unauthorized !"; //Customise as required
 }
 <h2>@ViewBag.Title.</h2> 

Cela affichera une page d'erreur personnalisée au lieu d'une page d'erreur générée par le navigateur.

Notez également que pour l'environnement ci-dessus, il n'est pas nécessaire de commenter le code à l'intérieur de la méthode RegisterGlobalFilters ajoutée par le modèle comme suggéré dans l'une des réponses.

Veuillez noter que je viens de couper et coller du code de mon projet de travail, j'ai donc utilisé Unauthorized à la place de NoPermissions d'OP dans le code ci-dessus.

13
Dush

depuis que je suis tombé sur un problème très similaire, je voulais apporter plus de lumière dessus.

customErrors capturera uniquement les exceptions HTTP réelles levées dans votre application ASP.NET. Le HttpStatusCodeResult ne lève cependant pas d'exception. Il écrit simplement une réponse avec le code d'état correspondant, ce qui est plus logique dans votre exemple.

Si vous exécutez sur IIS 7.0 ou supérieur, vous devez utiliser httpErrors maintenant, car cela vous montrera des pages d'erreur personnalisées dans tous les cas. Il s'agit d'un IIS réglage du niveau.

J'ai écrit un article de blog sur ce sujet pour expliquer les différences: http://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging

2
dustinmoris

Mise à jour

Vous n'avez qu'à faire cette redirection spéciale pour les erreurs 403. Toutes les 500 autres erreurs devraient prendre effet via votre defaultRedirect="/Error/Error" réglage dans customErrors. Cependant, vous devez supprimer ou commenter l'enregistrement HandleErrorAttribute dans le fichier App_Start/FilterConfig.cs pour que les erreurs personnalisées fonctionnent réellement. Sinon, cet attribut redirigera toutes les erreurs vers le fichier Error.cshtml dans le répertoire Views/Shared.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        // remove this line below
        //filters.Add(new HandleErrorAttribute());
    }
}

Réponse originale

Pour autant que je sache, vous ne pouvez pas utiliser customErrors dans le web.config pour gérer les erreurs 403 pour une raison quelconque. Je ressens votre douleur car cela semble être quelque chose qui devrait être aussi simple que le code que vous avez déjà, mais apparemment, les erreurs 403 sont traitées comme une préoccupation de serveur Web.

Ce que vous pouvez faire à la place est simplement de rediriger l'utilisateur vers la page "NoPermissions" souhaitée comme ceci:

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext context)
    {
        if (context.HttpContext.Request.IsAuthenticated)
        {
            context.Result = new RedirectToRouteResult(new RouteValueDictionary(new
            {
                action = "NoPermissions",
                controller = "Error",
                area = ""
            }));
        }
        else
        {
            base.HandleUnauthorizedRequest(context);
        }
    }
}

La demande aura un code d'état 200 au lieu d'un 403, mais si vous pouvez vivre avec cela, c'est une solution de contournement facile.

Voici une question similaire SO pour plus d'informations: Retour des erreurs personnalisées .

En outre, cet article explique comment suivre la route IIS: http://kitsula.com/Article/MVC-Custom-Error-Pages

0
ryanulit