asp.net Core3.1自定義權限體系-菜單和操作按鈕權限


我們在做項目項目,經常會碰到權限體系,權限體系屬於系統架構的一個最底層的功能,也是非常重要的功能,幾乎在每個項目都會用到。那么我們該如何設計一個比較合理的且擴展性較強的權限體系呢?

經過多天的摸索,參考多個系統以及自己的經驗,《沐雪微店系統 NetCore3.1》的權限體系是這樣的。

 

  • 一、首先確定幾個重要實體的關系:用戶,角色,權限;這三者之間的關系如下:

其中:

1、用戶與角色是1對多關系(  1個用戶只有1個角色,1個角色可以對應多個用戶);

2、角色與權限組是1對1關系( 1個角色只有1個權限組,1個權限組只有1個角色)。

3、一個權限組里包含1個菜單和多個操作按鈕;

4、操作按鈕預先定義好最多的情況的枚舉值;(比如  查看,新增,修改,刪除,審核,下載,確認,回復)

這樣的架構,相對來說比較合理,適合絕大多數系統使用了。(設計的越靈活,控制起來越困難,越困難越容易出現錯誤,所以要根據實際的情況控制靈活到什么程度即可;不要一口吃成胖子,想要一次性搞出無限靈活的權限系統。)

 

  • 二、對幾個實體進行CRUD單實體操作(增,刪,改,查)

 1、菜單的增刪改查;

2、權限組的增刪改查:

 

3、用戶的增刪改查:

 

  • 三、用代碼來實現權限系統

 大家在菜單管理頁面,應該注意到有3個字段:--編碼,鏈接地址和權限值;這些是我們寫代碼的時候需要用的。

1、創建一個控制器的父類--BaseController,這里只要有一個可以獲取當前登錄者的方法即可,類似如下代碼:

        /// <summary>
        /// 當前登錄者
        /// </summary>
        public PTLoginResp CurrentUser
        {
            get
            {
                PTLoginResp currentUser = new PTLoginResp();
                if (User.Identity.IsAuthenticated)
                {
                    var claimIdentity = (ClaimsIdentity)User.Identity;
                    string key = claimIdentity.FindFirst("tokenid").Value;
                    currentUser.id = LoginCredentials.PFDecodeRedisKeyOfUserId(key);

                    currentUser.user_name = claimIdentity.FindFirst("user_name").Value;
                    currentUser.real_name = claimIdentity.FindFirst("real_name").Value;
                    currentUser.mobile_phone = claimIdentity.FindFirst("mobile_phone").Value;
                    currentUser.role_id = ConvertHelper.LongParse(claimIdentity.FindFirst("role_id").Value, 0);

                }
                return currentUser;
            }
        }
View Code

2、創建具體的業務控制器和相應的Action,並且集成BaseController;

3、創建一個Action的權限屬性特性方法,比如下面代碼:

    /// <summary>
    /// Action的權限屬性
    /// </summary>
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class ActionAuthDescriptorAttribute : System.Attribute
    {

        public ActionAuthDescriptorAttribute(string NavCode, AuthTypeEnum AuthType)
        {
            this.NavCode = NavCode;
            this.AuthType = AuthType;

        }
        /// <summary>
        /// 權限組code
        /// </summary>
        public string NavCode { get; set; }

        /// <summary>
        /// 權限操作的枚舉值,比如Show
        /// </summary>
        public AuthTypeEnum AuthType { get; set; }

    }

這樣,我們就可以在Action上加上這個特性了:

        /// <summary>
        /// 《沐雪微店系統 Netcore 3.1》添加管理員頁面
        /// </summary>
        /// <returns></returns>
        [ActionAuthDescriptor("manager_mgr", AuthTypeEnum.Add)]
        public async Task< ActionResult> Create()
        {
            ManagerInfo managerAdd = new ManagerInfo();
            managerAdd.using_type = UsingTypeEnum.sys.ToString();
            managerAdd.is_lock = false;

            List<muxue_role> roleList =await  _roleService.GetRoleList(UsingTypeEnum.sys);
            roleList = roleList.FindAll(p => p.is_sys == false);
            ViewBag.roleList = roleList;

            return View(managerAdd);
        }

4、開始寫權限驗證過濾器了PrivilegeFilter:

驗證的大概邏輯如下:

 /// <summary>
        /// 《沐雪微店系統 Netcore 3.1》權限驗證邏輯
        /// (集成BaseController的控制器,需要登錄后才可以)
        /// 1、看下Controller是否有AllRightsAttribute;
        /// 2、看下Action是否有AllRightsAttribute,是否有ActionAuthDescriptorAttribute
        /// 3、(1)若Action有AllRightsAttribute,則說明任何登錄者都可以訪問;
        ///    (2)若Action沒有AllRightsAttribute,但是Controller上有,則說明任何登錄者都可以訪問;
        ///    (3)若Action和Controller都沒有,並且Aciton也沒有ActionAuthDescriptorAttribute, 則任何人都不可以訪問;
        /// 4、看下Action是否有ActionAuthDescriptorAttribute,則任何人都不可以訪問;
        /// 5、若有ActionAuthDescriptorAttribute,則進行判斷該Action是否有該角色的權限;
        /// </summary>
        /// <param name="context"></param>

重點的代碼如下:

 public override void OnActionExecuting(ActionExecutingContext context)
        {

            var controller = context.Controller as BaseController;
            if (controller == null)
            {
                base.OnActionExecuting(context);
                return;
            }

            if (controller.CurrentUser == null)
            {
                //《沐雪微店系統 Netcore 3.1》去登錄
                // context.HttpContext.ChallengeAsync().Wait();
                base.OnActionExecuting(context);
                return;
            }

            string requestMethod = context.HttpContext.Request.Method.ToLower();


            ControllerActionDescriptor ad = context.ActionDescriptor as ControllerActionDescriptor;
            bool isControllerAllRights = ad.ControllerTypeInfo.IsDefined(typeof(AllRightsAttribute), false);
            bool isActionAllRights = ad.MethodInfo.IsDefined(typeof(AllRightsAttribute), false);
            bool isActionAuthDescriptor = ad.MethodInfo.IsDefined(typeof(ActionAuthDescriptorAttribute), false);
            if (!isControllerAllRights && !isActionAllRights && !isActionAuthDescriptor)
            {
                //沒有權限訪問
                if (requestMethod == "get")
                {
                    context.Result = new RedirectResult("/Error/Index?msg=沒有權限");
                    base.OnActionExecuting(context);
                    return;
                }
                else
                {
                    context.Result = new JsonResult(NoPrivPostJsonResult());
                    base.OnActionExecuting(context);
                    return;
                }
            }
            if (isActionAllRights)
            {
                base.OnActionExecuting(context);
                return;
            }
            if (isControllerAllRights && !isActionAllRights && !isActionAuthDescriptor)
            {
                base.OnActionExecuting(context);
                return;
            }

            if (isActionAuthDescriptor)
            {
                var authorizeAttr = ad.MethodInfo.GetCustomAttributes(typeof(ActionAuthDescriptorAttribute), false).FirstOrDefault() as ActionAuthDescriptorAttribute;
                string navCode = authorizeAttr.NavCode;
                AuthTypeEnum authType = authorizeAttr.AuthType;

                long current_role_id = controller.CurrentUser.role_id;
                bool hasRolePriv = _roleprivilegeService.HasRolePriv(current_role_id, navCode, authType).Result;
                if (!hasRolePriv)
                {//沒有權限
                    if (requestMethod == "get")
                    {
                        context.Result = new RedirectResult("/Error/Index?msg=沒有權限");
                        base.OnActionExecuting(context);
                        return;
                    }
                    else
                    {
                        context.Result = new JsonResult(NoPrivPostJsonResult());
                        base.OnActionExecuting(context);
                        return;
                    }
                }
            }

            base.OnActionExecuting(context);

        }

將這個Filter添加到StartUp里:

            services.AddMvc(options =>
            {
                if (!env.IsDevelopment())
                {
                }
                options.Filters.Add<LogstashFilter>();
                options.Filters.Add<PrivilegeFilter>();//權限驗證
                options.Filters.Add<XcActionFilter>();
                options.Filters.Add<GlobalExceptions>();
            })

這樣就完成了權限控制了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM