zoukankan      html  css  js  c++  java
  • 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>();
                })

    这样就完成了权限控制了。

  • 相关阅读:
    eclipse中解决git分支合并冲突
    git 放弃本地修改,强制拉取更新
    廖雪峰Git入门教程
    如何实现Proxifier只代理部分程序
    Proxifier代理工具简介和下载
    Navicat Premium 12.0.18安装与激活
    Teamviewer远程控制
    夜神安卓模拟器下载及简介
    Fiddler2如何对Android应用进行抓包
    谷歌浏览器添加JSON-handle插件
  • 原文地址:https://www.cnblogs.com/puzi0315/p/13557251.html
Copyright © 2011-2022 走看看