asp.net Core3.1自定义权限体系-菜单和操作按钮权限
阅读原文时间:2023年07月13日阅读: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, );

            }  
            return currentUser;  
        }  
    }

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:

验证的大概逻辑如下:

///

/// 《沐雪微店系统 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是否有该角色的权限; ///
///

重点的代码如下:

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>();  
        })

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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章