文章出處

回到目錄

對于一個后臺管理系統來說,你的權限設計與安全是重中之重,當你為一個權限分配一些菜單后,當這個權限的用戶沒有菜單權限時,這個菜單的URL是不可以被用戶訪問的,而在之前的設計中,沒有考慮到這點,所以本次Lind.DDD.Manager的升級中,需要把這塊完善一下,將會在8月的Lind.DDD中奉獻給大家,敬請期待!

思路

用戶訪問

==>

mvc根據url找到controller/action

==>

判斷這個URL是否為庫中定義的URL(排除非正常URL,PartialView產生的URL)

==>

判斷用戶是否有這個URL的權限

==>

正常訪問

層關系圖

實現

使用了MVC環境下的AOP方法攔截技術,它主要通過過濾器(AuthorizeAttribute)來實現對action的攔截,然后注入自己的代碼,這也是MVC幾大過濾器帶給我們的驚喜!

AuthorizeAttribute 為我們提供了一個用戶授權的過濾器,當用戶訪問Action之前,它將被執行

   // 摘要:
    //     表示一個特性,該特性用于限制調用方對操作方法的訪問。
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
    {
        // 摘要:
        //     初始化 System.Web.Mvc.AuthorizeAttribute 類的新實例。
        public AuthorizeAttribute();

        // 摘要:
        //     獲取或設置用戶角色。
        //
        // 返回結果:
        //     用戶角色。
        public string Roles { get; set; }
        //
        // 摘要:
        //     獲取此特性的唯一標識符。
        //
        // 返回結果:
        //     此特性的唯一標識符。
        public override object TypeId { get; }
        //
        // 摘要:
        //     獲取或設置授權用戶。
        //
        // 返回結果:
        //     授權用戶。
        public string Users { get; set; }

        // 摘要:
        //     重寫時,提供一個入口點用于進行自定義授權檢查。
        //
        // 參數:
        //   httpContext:
        //     HTTP 上下文,它封裝有關單個 HTTP 請求的所有 HTTP 特定的信息。
        //
        // 返回結果:
        //     如果用戶已經過授權,則為 true;否則為 false。
        //
        // 異常:
        //   System.ArgumentNullException:
        //     httpContext 參數為 null。
        protected virtual bool AuthorizeCore(HttpContextBase httpContext);
        //
        // 摘要:
        //     處理未能授權的 HTTP 請求。
        //
        // 參數:
        //   filterContext:
        //     封裝有關使用 System.Web.Mvc.AuthorizeAttribute 的信息。filterContext 對象包括控制器、HTTP 上下文、請求上下文、操作結果和路由數據。
        protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext);
        //
        // 摘要:
        //     在過程請求授權時調用。
        //
        // 參數:
        //   filterContext:
        //     篩選器上下文,它封裝有關使用 System.Web.Mvc.AuthorizeAttribute 的信息。
        //
        // 異常:
        //   System.ArgumentNullException:
        //     filterContext 參數為 null。
        public virtual void OnAuthorization(AuthorizationContext filterContext);
        //
        // 摘要:
        //     在緩存模塊請求授權時調用。
        //
        // 參數:
        //   httpContext:
        //     HTTP 上下文,它封裝有關單個 HTTP 請求的所有 HTTP 特定的信息。
        //
        // 返回結果:
        //     對驗證狀態的引用。
        //
        // 異常:
        //   System.ArgumentNullException:
        //     httpContext 參數為 null。
        protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
    }

對于我們的菜單權限過濾器,需要繼承它,我們起名為ManagerUrlAttribute,下面是大叔設計的代碼,大家可以作為參考

    /// <summary>
    /// 后臺URL菜單的權限
    /// 需要考慮到PartialView的問題
    /// </summary>
    public class ManagerUrlAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// 驗證失敗后所指向的控制器和action
        /// 可以在使用特性時為它進行賦值
        /// </summary>
        public ManagerUrlAttribute(string failControllerName = "Home", string failActionName = "Login")
        {
            _failControllerName = failControllerName;
            _failActionName = failActionName;
        }
        /// <summary>
        /// 出錯時要跳轉的控制器
        /// </summary>
        string _failControllerName;
        /// <summary>
        /// 出錯時要跳轉的action
        /// </summary>
        string _failActionName;
        /// <summary>
        /// 菜單倉儲
        /// </summary>
        static IExtensionRepository<WebManageMenus> menuRepository = new ManagerEfRepository<WebManageMenus>(new ManagerContext());
        /// <summary>
        /// 所有已經定義的菜單項
        /// </summary>
        static List<WebManageMenus> allMenuList = menuRepository.GetModel().ToList();

        public override void OnAuthorization(AuthorizationContext filterContext)
        {

            var menuIdArr = Array.ConvertAll<string, int>(CurrentUser.ExtInfo.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries), i => int.Parse(i));
            var menuUrlArr = allMenuList.Where(i => menuIdArr.Contains(i.Id)).Select(i => i.LinkUrl).ToList();
            var controllerName = filterContext.RouteData.Values["controller"].ToString();
            var actionName = filterContext.RouteData.Values["action"].ToString();
            var isValid = allMenuList.FirstOrDefault(i => i.LinkUrl == "/" + controllerName + "/" + actionName) != null;//是否為有效的URL,過濾分布視圖

            //當前為正常頁面,不是分布視圖
            if (isValid)
            {
                //沒有當前URL的權限,跳到登陸頁
                if (!menuUrlArr.Contains("/" + controllerName + "/" + actionName))
                {
                    filterContext.Result = new RedirectToRouteResult("Default", new RouteValueDictionary { 
                              { "Action",_failActionName },
                              { "Controller", _failControllerName} });
                }
            }
        }

    }

本代碼解決了分布視圖在過濾器中的尷尬,將分布視圖產生的action進行過濾,我們先將所有定義的菜單URL取出來,然后用戶訪問時,先判斷當前URL是否為已經定義的URL,如果是,再進行權限的比較.

 回到目錄


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()