我们在做项目项目,经常会碰到权限体系,权限体系属于系统架构的一个最底层的功能,也是非常重要的功能,几乎在每个项目都会用到。那么我们该如何设计一个比较合理的且扩展性较强的权限体系呢?

经过多天的摸索,参考多个系统以及自己的经验,《沐雪微店系统 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:

验证的大概逻辑如下:

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

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

asp.net Core3.1自定义权限体系-菜单和操作按钮权限的更多相关文章

  1. [转]PostgreSQL 逻辑结构 和 权限体系 介绍

    摘要: 本文旨在帮助用户理解PostgreSQL的逻辑结构和权限体系,帮助用户快速的理解和管理数据库的权限. 逻辑结构 最上层是实例,实例中允许创建多个数据库,每个数据库中可以创建多个schema,每 ...

  2. Asp.net Identity身份与权限体系设计

    1 Identity 介绍 2 授权系统 图1 体系结构 3 自定义 Attribute 自定义 Attribute 继承于 AuthorizeAttribute,AuthorizeAttribute ...

  3. .net core3.1 abp动态菜单和动态权限(思路) (二)

    ps:本文需要先把abp的源码下载一份来下,跟着一起找实现,更容易懂 在abp中,对于权限和菜单使用静态来管理,菜单的加载是在登陆页面的地方(具体是怎么知道的,浏览器按F12,然后去sources中去 ...

  4. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(20)-权限管理系统-根据权限获取菜单

    原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(20)-权限管理系统-根据权限获取菜单 不知不觉到20讲,真是漫长的日子,可惜最近工作挺忙,要不可以有更多 ...

  5. vue的自定义指令控制菜单权限

    用户登录后,选择子节点,节点中含有多个菜单,可以根据后台返回的权限数据进行权限控制 在vue上挂载自定义指令方法,根据后台返回权限移除相应节点 import Cookies from "js ...

  6. 浅谈Oracle权限体系

    对于数据库来讲,安全性的重要程度不言而喻,今天我们就来聊一聊Oracle的权限体系. 1.账户管理 在此之前,先解释下一个容易混淆的概念:模式.所谓模式,指的是用户账户所拥有的一组对象(比如表,索引, ...

  7. sqlserver权限体系(上)

    简介 权限两个字,一个权力,一个限制.在软件领域通俗的解释就是哪些人可以对哪些资源做哪些操作. 在SQL Server中,”哪些人”,“哪些资源”,”哪些操作”则分别对应SQL Server中的三个对 ...

  8. 理解SQL Server中的权限体系(上)----主体

    原文:http://www.cnblogs.com/CareySon/archive/2012/04/10/mssql-security-principal.html 简介 权限两个字,一个权力,一个 ...

  9. [2017-08-21]Abp系列——如何使用Abp插件机制(注册权限、菜单、路由)

    本系列目录:Abp介绍和经验分享-目录 Abp的模块系统支持插件机制,可以在指定目录中放置模块程序集,然后应用程序启动时会搜索该目录,加载其中所有程序集中的模块. 如何使用这套机制进行功能插件化开发? ...

随机推荐

  1. Python read和write方法

    Python read和write方法: read(): 从文件中读取字符串 注:Python 字符串可以是二进制数据,而不仅仅是文字. 语法: 文件对象.read([count]) count:打开 ...

  2. PHP 是什么?简介下

    PHP 是服务器端脚本语言. 您应当具备的基础知识 在继续学习之前,您需要对以下知识有基本的了解: HTML CSS PHP 是什么? PHP(全称:PHP:Hypertext Preprocesso ...

  3. PHP rewind() 函数

    定义和用法 rewind() 函数将文件指针的位置倒回文件的开头. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE. 语法 rewind(file) 参数 描述 file 必需.规定已打 ...

  4. luogu P2525 Uim的情人节礼物 其之壱

    LINK:Uim的情人节礼物·其之壱 壱 古代通壹 常在日文中出现. 完全可以使用STL -->prev_permutation来解决. 不过我简单了解了一下康托展开. 这是一个一个排列对应一个 ...

  5. bzoj 4448 [Scoi2015]情报传递 主席树

    比较套路的题目. 可以发现难点在于某个点的权值动态修改 且我们要维护树上一条路径上的点权>x的个数. 每个点都在动态修改 这意味着我们的只能暴力的去查每个点. 考虑将所有可以动态修改的点变成静态 ...

  6. 小程序中 radio 的一个坑,到底 checked 该赋什么值?

    https://blog.csdn.net/henryhu712/article/details/83059365

  7. Idea 提交配置说明

    Idea 提交配置说明# Auto-update after commit :自动升级后提交 keep files locked :把文件锁上,我想这应该就只能你修改其他开发人不能修改不了的功能 在你 ...

  8. Flink状态妙用

    本文主要介绍福布湿在flink实时流处理中,state使用的一些经验和心得.本文默认围观的大神已经对flink有一定了解,如果围观过程中发现了有疑问的地方,欢迎在评论区留言. 1. 状态的类别 1.1 ...

  9. Java 集合框架综述,这篇让你吃透!

    一.集合框架图 简化图: 说明:对于以上的框架图有如下几点说明 1.所有集合类都位于java.util包下.Java的集合类主要由两个接口派生而出:Collection和Map,Collection和 ...

  10. Bytom DAPP 开发流程

    从目前已经发布的DAPP来看,DAPP架构大致可以分成3种类型:插件钱包模式.全节点钱包模式和兼容模式. 插件钱包模式是借助封装了钱包的浏览器插件通过RPC协议与区块链节点通信,插件在运行时会将Web ...