1. 程式人生 > >ASP.NET MVC4 自定義許可權(角色)驗證

ASP.NET MVC4 自定義許可權(角色)驗證

開發系統的時候,兩個基本的模組是少不了的,那就是 —— 身份驗證 和許可權。上一篇文章我們介紹了ASP.NET MVC 身份驗證,今天我們來說一下許可權管理。

1. 需求:

當普通使用者 進行編輯、刪除操作時,系統拒絕使用者的訪問,若訪問為非同步操作,則返回 JSON資料,給出提示訊息(許可權不足),若為同步操作,則跳轉登入頁。

2. 效果:

當我以普通使用者身份(user)登陸後,進行刪除操作,系統拒絕了我的操作,並將訊息返回給了我。

下面我們一步步介紹一下是如何實現的。

許可權管理

3. 自定義實現的實現

3.1 程式碼效果

當我 希望 Create方法只能 管理員具有許可權的建立的時候,在該方法 加上 這個特性。RoleAuthorize 是我們自定義 的許可權過濾器,下一小節中將介紹它。將該特性放在 Action,將對請求進行過濾,不符合許可權請求,將被篩選。

其實 許可權過濾器 它也屬於過濾器的範疇

許可權控制程式碼

3.2 實現原理

ASP.NET MVC 自定義許可權控制,是通過 繼承 AuthorizeAttribute 類來實現的。下面介紹一下 AuthorizeAttribute 的核心方法,需要我們進行復寫,自定義。
1、OnAuthorization: 核心方法,許可權過濾器的入口。
2、AuthorizeCore : 核心驗證方法,驗證的自定義邏輯要放在這個方法裡。
3、HandleUnauthorizedRequest : 驗證失敗後,呼叫的處理方法,處理驗證失敗,放在這個方法裡。

3.3 實現程式碼

下面是程式碼,在這兒簡單介紹一下 自定義許可權驗證的邏輯。

1、 複寫 OnAuthorization 方法,在該方法裡 執行父類的OnAuthorization方法。(個人感覺可以省略)
2、複寫 AuthorizeCore方法,上面已經介紹過了,這個方法裡 描述的是核心驗證邏輯,父類的
OnAuthorization 裡 是呼叫了 AuthorizeCore 這個方法去 驗證 是否具有許可權的。

這裡還涉及到了一點 多型 的 知識(我們在 複寫 父類的方法後,父類執行 AuthorizeCore 的方法,是子類的AuthorizeCore 的方法)

3、父類的 OnAuthorization 在使用 子類AuthorizeCore

驗證後,驗證成功後,會讓請求 繼續向下執行,

如果失敗,與上面同樣的道理將會呼叫子類的HandleUnauthorizedRequest方法,去處理不具有許可權
的請求。

上面介紹了原理,下面我簡單說一下 是 如何自定義AuthorizeCore驗證方法的,以及驗證失敗後是如
何去處理的HandleUnauthorizedRequest

AuthorizeCore 驗證方法思路:

  • 在這個方法裡首先 httpContext.Request.IsAuthenticated 進行身份驗證,身份驗證通過之後;
  • 獲取身份驗證的Cookie 並將 我存在cookie裡的使用者資訊,提取出來。(我儲存了 使用者名稱,角色,ID,頭像等)
  • 獲取到使用者資訊之後,你允許什麼樣的使用者通過吶?那就是你隨意自定義了,比如說:我定義的允許就是 你的許可權(RoleID)大於我設定的許可權,那你就可以通過,否則我就返回false,而後就進入了 HandleUnauthorizedRequest方法。

HandleUnauthorizedRequest 驗證失敗請求處理 思路

  • 如果未非同步請求,使用 filterContext.Result返回Json 資料。
  • 如果未同步請求,使用 base.HandleUnauthorizedRequest(filterContext) 父類的處理方法去解決就可以了(父類的處理方式是跳 登入頁)
/// <summary>
/// 自定義許可權(角色)驗證
/// </summary>
public class RoleAuthorizeAttribute: AuthorizeAttribute
{
     /// <summary>
     /// 驗證入口
     /// </summary>
     /// <param name="filterContext"></param>
     public override void OnAuthorization(AuthorizationContext filterContext)
     {
         base.OnAuthorization(filterContext);
     }

     /// <summary>
     /// 驗證核心程式碼
     /// </summary>
     /// <param name="httpContext"></param>
     /// <returns></returns>
     protected override bool AuthorizeCore(HttpContextBase httpContext)
     {
         byte roleid = 0;
         AdminModel loginUser = new AdminModel();
         if (! httpContext.Request.IsAuthenticated)
         {
             //非非同步請求,跳轉登入頁,非同步請求則交給身份驗證過濾器處理(程式碼在執行的時候,將先執行身份驗證,也就是AuthorizeAttribute類,而後才會執行過濾器。 所以如果說,身份驗證是通過 過濾器實現的話,這一步判斷是必須的。)
             if (!httpContext.Request.IsAjaxRequest())
              {
                  FormsAuthentication.RedirectToLoginPage();//重定向會登入頁
              }
              return false;//未登入返回 false
         }
         else
         {
             //登入狀態獲取使用者資訊
             var cookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
             var ticket = FormsAuthentication.Decrypt(cookie.Value);
             loginUser = new JavaScriptSerializer().Deserialize<AdminModel>(ticket.UserData);
             roleid = FrameworkStatic.GetRoleID(this.Roles);
         }
         return IsAllow(loginUser.RoleID, roleid);
     }

     /// <summary>
     /// 驗證失敗處理
     /// </summary>
     /// <param name="filterContext"></param>
     protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
     {
         if (filterContext.HttpContext.Request.IsAjaxRequest())
         {
             filterContext.Result = new JsonResult
             {
                 Data = new
                 {
                     Status = -1,
                     Message = "許可權不足,伺服器已拒絕您的操作!"
                 },
                 JsonRequestBehavior = JsonRequestBehavior.AllowGet
             };
         }
         else
             base.HandleUnauthorizedRequest(filterContext);
         return;
     }

     /// <summary>
     /// 判斷當前使用者許可權是否大於目標操作許可權(許可權向下相容)
     /// </summary>
     /// <param name="currentRoleId">當前角色</param>
     /// <param name="targetRoleId">目標角色</param>
     /// <returns>是否允許</returns>
     private bool IsAllow(byte currentRoleId,byte targetRoleId)
     {
         return currentRoleId >= targetRoleId;
     }
}

參考博文