Asp.net-Mvc

為什麼AuthorizeAttribute會重定向到登錄頁面進行認證和授權失敗?

  • October 26, 2008

在 ASP.NET MVC 中,您可以使用 標記控制器方法AuthorizeAttribute,如下所示:

[Authorize(Roles = "CanDeleteTags")]
public void Delete(string tagName)
{
   // ...
}

這意味著,如果目前登錄的使用者不是“CanDeleteTags”角色,則永遠不會呼叫控制器方法。

不幸的是,對於失敗,AuthorizeAttribute返回HttpUnauthorizedResult,它總是返回 HTTP 狀態程式碼 401。這會導致重定向到登錄頁面。

如果使用者沒有登錄,這很有意義。但是,如果使用者已經登錄,但不是所需的角色,將他們發送回登錄頁面會令人困惑。

似乎AuthorizeAttribute將身份驗證和授權混為一談。

這在 ASP.NET MVC 中似乎有點疏忽,還是我遺漏了什麼?

我不得不煮一個DemandRoleAttribute將兩者分開的。當使用者未通過身份驗證時,它會返回 HTTP 401,將其發送到登錄頁面。當使用者登錄但不是所需的角色時,它會創建一個NotAuthorizedResult。目前這會重定向到錯誤頁面。

當然我不必這樣做?

最初開發時,System.Web.Mvc.AuthorizeAttribute 做的是正確的事 - HTTP 規範的舊版本使用狀態程式碼 401 表示“未授權”和“未驗證”。

從原始規範:

如果請求已包含授權憑證,則 401 響應表示已拒絕對這些憑證的授權。

實際上,您可以在此處看到混亂-它在表示“身份驗證”時使用了“授權”一詞。然而,在日常實踐中,當使用者通過身份驗證但未授權時,返回 403 Forbidden 更有意義。使用者不太可能擁有第二組可以授予他們訪問權限的憑據 - 到處都是糟糕的使用者體驗。

考慮大多數作業系統 - 當您嘗試讀取您無權訪問的文件時,您不會看到登錄螢幕!

值得慶幸的是,HTTP 規範已更新(2014 年 6 月)以消除歧義。

來自“超文本傳輸協議(HTTP/1.1):身份驗證”(RFC 7235):

401(未授權)狀態碼表示該請求尚未應用,因為它缺少目標資源的有效身份驗證憑據。

來自“超文本傳輸協議 (HTTP/1.1):語義和內容”(RFC 7231):

403(Forbidden)狀態碼表示伺服器理解請求但拒絕授權。

有趣的是,在 ASP.NET MVC 1 發佈時,AuthorizeAttribute 的行為是正確的。現在,行為不正確 - HTTP/1.1 規範已修復。

與其嘗試更改 ASP.NET 的登錄頁面重定向,不如從源頭解決問題更容易。您可以在網站的預設命名空間中創建一個具有相同名稱 ( AuthorizeAttribute)的新屬性(這非常重要),然後編譯器會自動選擇它而不是 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((int)System.Net.HttpStatusCode.Forbidden);
       }
       else
       {
           base.HandleUnauthorizedRequest(filterContext);
       }
   }
}

引用自:https://stackoverflow.com/questions/238437