2011-08-11 94 views
14

我重寫類來進行自定義授權設置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 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, 我在這裏失蹤,任何想法

回答

11

只是一個小提示/筆記之外最大B.答案:

當我使用自定義的錯誤,我做的ErrorsController和取消授權的ActionResult和做到以下幾點:

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

這樣我可以添加額外的信息,或做在我的控制器其他動作,例如:

  • 就像有人試圖訪問認證區域的日誌記錄到數據庫一樣。
  • 錯誤計數。
  • 也許他們可以用來發送管理信息的錯誤或報告表單。
  • ...

這種方式,你有什麼發生了一些更多的控制。

+0

其實我在做同樣的事情,共享是控制器和未經授權的行爲,但我仍然收到相同的默認HTTP 403頁面錯誤,而不是我定義的頁面 –

+1

非常有幫助的鏈接http://stackoverflow.com/questions/2504923/how -to-redirect-authorize-to-loginurl-only-when-roles-are-not-used –

+2

@SaboorAwan。我也嘗試過,沒有運氣。控制器方法永遠不會被調用。您是否通過此答案或您發佈的鏈接解決了問題? – Marco

-1

對我來說似乎是HttpStatusCodeResult(403)是錯誤的如果分支。在我看來,代碼應該是這樣的:

+1

您可能想要測試它......它規避了Authenticated時的授權要求。 – JustinStolle

3

或者你也可以做到這一點的替代解決方案,而不是使用:在您的控制器/ BaseController

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

,並重寫方法onException的(ExceptionContext filterContext):

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

,你可以把它改成

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

我的問題和我在寫m時一模一樣您擁有自定義的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的路線。

8

我知道這是一個非常古老的問題,但我發佈的人可能有同樣的問題。像我一樣,我遇到了同樣的問題並解決了它。如果你想觸發web.config中的customErrors元素,你可以試試下面。

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

完美,比其他解決方案更容易。 – Guillaume

+2

你把這個放在哪裏?很高興補充。它可以是區域特定的嗎? – CularBytes

+0

@RageCompex您可以將它們放入您的自定義屬性類中。你能否詳細說明「特定區域」? – user3110409

0

如何在mvc中處理401(未授權),403(禁止)和500(內部服務器錯誤)。對於ajax/non-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過濾,所以我想要拒絕用戶=「?」。

+0

你應該實際上能夠將F12(resharper反編譯?ms符號服務器?)中的:ControllerActionInvoker,HandleErrorAttribute,AuthorizeAttribute。這是非常有啓發性的閱讀。 ControllerActionInvoker以不同的方式使用4種過濾器類型中的每一種。 (auth,action,result,exception)例如,轉到您的控制器,在基類「Controller」上按F12,在「IAuthorizationFilter」上按F12,在「OnAuthorization」上按Shift-F12。 –