web-dev-qa-db-ja.com

ASP.NET MVC 5カスタムエラーページ

ASP.NET MVC 5アプリケーションでは、次のようなカスタム認証属性を使用しています。

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

Web.configのsystem.webセクションで、次のようなエラーパスに言及しました。

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

ただし、/Error/NoPermissionsのカスタムエラーページにリダイレクトされることはありません。代わりに、ブラウザは"HTTPエラー403.0-禁止"という一般的なエラーページを表示します。

29
Haider

みんなに感謝しますが、問題は403コードではありません。実際、問題は403を返そうとしていた方法にありました。HttpExceptionを返す代わりにHttpStatusCodeResultをスローするようにコードを変更しただけで、すべてが動作するようになりました。 HttpException例外をスローすることでHTTPステータスコードを返すことができ、私のcustomErrors構成はそれらすべてをキャッチします。 HttpStatusCodeResultが私が期待していた通りの仕事をしていない可能性があります。

私はちょうど交換しました

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

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

それでおしまい。

ハッピーコーディング。

18
Haider

[1]:Web.configからすべての 'customErrors'と 'httpErrors'を削除します

[2]:「App_Start/FilterConfig.cs」が次のようになっていることを確認します。

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

[3]: 'Global.asax'に次のメソッドを追加します。

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]:「Controllers/ErrorPageController.cs」を追加します

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

[5]:「Views/Shared/Error.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

:D

44
ubik404

私もこの問題を抱えていました。 OPの質問のコードは、<system.web>ファイルのweb.configセクションのカスタムエラーコードを除き、完全に機能しています。この問題を解決するには、次のコードを<system.webServer>に追加する必要がありました。 ‘webserver’の代わりに‘web’に注意してください。

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

誰かが次の環境を使用している場合、完全なソリューションは次のとおりです。

環境:

  • Visual Studio 2013アップデート4
  • ASP.NET MVC 5を搭載したMicrosoft .NET Framework 4.5.1
  • プロジェクト:MVCと認証を備えたASP.NET Webアプリケーション:個別のユーザーアカウントテンプレート

カスタム属性クラス:

次のクラスをWebサイトのデフォルト名前空間に追加します。ここで受け入れられた答えで説明されている理由 スタックオーバーフローの質問:なぜAuthorizeAttributeは認証および承認の失敗のためにログインページにリダイレクトするのですか?

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

次に、web.configファイルに次のコードを追加します

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

次の記事で説明します これについての詳細:ASP.NET MVC:承認属性の改善(403禁止)

web.configのhttpErrorsこの記事のセクション: ASP.NET MVC 5のエラーページとエラーログをわかりやすく説明する

次に、ErrorController.csをControllersフォルダーに追加します

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

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

}

次に、UnAuthorized.cshtmlをView/Sharedフォルダーに追加します

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

これにより、ブラウザで生成されたエラーページではなく、カスタマイズされたエラーページが表示されます。

また、上記の環境では、回答の1つで提案されているように、テンプレートによって追加されたRegisterGlobalFiltersメソッド内のコードをコメント化する必要はありません。

作業中のプロジェクトからコードをカットアンドペーストするだけなので、上記のコードではOPのUnauthorizedの代わりにNoPermissionsを使用したことに注意してください。

13
Dush

よく似た問題に遭遇したので、それをもっと明らかにしたかったのです。

customErrorsは、ASP.NETアプリケーションでスローされた実際のhttp例外のみをキャプチャします。ただし、HttpStatusCodeResultは例外をスローしません。それは、対応するステータスコードを使用して応答を書き込むだけです。これは、この例ではより意味があります。

IIS 7.0以降で実行している場合は、すべてのケースでカスタムエラーページが表示されるため、httpErrorsを使用する必要があります。これはIISレベル設定。

違いを説明するために、これに関するブログ記事全体を書きました: http://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging

2
dustinmoris

更新

403エラーに対してのみ、特別なリダイレクトを行う必要があります。他の500エラーはすべて、defaultRedirect="/Error/Error"customErrorsの設定。ただし、カスタムエラーを実際に機能させるには、App_Start/FilterConfig.csファイルのHandleErrorAttribute登録を削除するかコメント化する必要があります。それ以外の場合、その属性はすべてのエラーをViews/SharedディレクトリのError.cshtmlファイルにリダイレクトします。

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

元の回答

私が知る限り、何らかの理由でweb.configでcustomErrorsを使用して403エラーを処理することはできません。既に持っているコードと同じくらい単純なもののように思えますが、403エラーはWebサーバーの問題として扱われているように見えるので、あなたの痛みを感じます。

代わりにできることは、次のようにユーザーを目的の「NoPermissions」ページにリダイレクトするだけです。

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

リクエストには、403ではなく200のステータスコードが含まれますが、それをそのまま使用できる場合、これは簡単な回避策です。

同様のSO詳細情報の質問: Returning custom errors

また、この記事では、IISルート: http://kitsula.com/Article/MVC-Custom-Error-Pages

0
ryanulit