一、前言

实际上权限系统老早之前我就在一直开发,大概在刚毕业没多久就想一个人写一个系统,断断续续一直坚持到现在,毕竟自己亲动手自写的系统才有收获,本篇仅介绍权限。

  小小系统上不了台面,望各位大神勿喷。

二、系统介绍

目前采用的是.Net Core微服务的方式实现,本文不讨论具体的中间件主要是(ocelot + consul等),一直参考微软的  eShopOnContainers ,进行简单的实现,但是ORM是用的Dapper,并简单进行封装  传送门 ,当然自己也封装了一些简单的插件进行复用:传送门,如下:

三、权限系统

权限系统实现很简单,权限的划分我觉得可以分为三种:

1、菜单权限2、按钮权限3、数据权限

简单介绍下:1、菜单权限。表示用户是否能够访问该页面(角色挂钩)

      2、按钮权限。表示用户是否能够操作该页面上的功能(角色挂钩)

      3、数据权限。表示用户访问页面时进行数据筛选(该功能暂未实现,这个要与具体的业务结合才能写),与部门挂钩,这个不太好理解,当然一般的权限系统这个功能也不会做,举个简单例子,OA系统里面我查看我的工资条,我应该只能看到我自己的数据,但是我的部门经理,他可以有权限看到该部门的全部数据,这个就是数据权限。

为什么写这个系统?

  之前待过好几家公司,发现他们的系统都是对菜单进行分配,当然了,业务需求只要这个就当我没说,我只是觉得这样做太不安全并且我觉得之前系统的实现方式可以进行一些优化,所以就一直写到现在,可能代码质量不如哪些大神的优秀,系统在我看来太小,就简单搭了个框架实现。你过条小水沟,没必要造条桥。

要使用该系统前提条件:前端:Sea.js和Vue,对于sea.js,在前端这块感觉已经没多少人用了,但是这中CMD思想是不会被淘汰的,你看最近比较火的layerui也是的,对于Vues只是简单的应用,也就用到双向绑定而已,开发复杂的页面确实比较方便,但是简单的页面就得不偿失了。

           后端:consul、rabbitmq ,具体怎么安装不在描述

大概的用户访问流程描述如下:

用户登录      =====》  获取该用户角色   ===》  通过角色获取该角色对应的权限 并集  ===>返回相应数据

      sys_user_role      sys_role_resource

系统关系图如下(MySQL):

具体功能实现请看代码,这里不做阐述,菜单权限的分配通过角色表和菜单表的关联表操作即可,但是按钮的权限分配如何实现?我的实现方式是:把按钮的操作也看成一种菜单的资源分配,只不过比较特殊,我这里不仅仅是对按钮的显示进行控制,我做的比较绝,也对后台方法访问权限也做了控制,这样比较安全,对于按钮权限的控制,实际上是明确的,比方说,一个删除按钮,它只能对应后台的一个删除方法,这个方法是明确的,对于页面的按钮的类型和个数是固定的,不然你没办法分配,基于这个前提,我对菜单的生成进行代码控制从而达到控制目的,因此,菜单和按钮和在一起称之为资源表 sys_resource 。具体的实现代码也不是很复杂,一层一层判断即可,权限过滤器如下:

     public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
public UrlAndButtonType UrlAndButtonType { get; } public PermissionAuthorizationRequirement(string url, ButtonType buttonType, bool isPage)
{
UrlAndButtonType = new UrlAndButtonType()
{
Url = url,
ButtonType = (byte)buttonType,
IsPage = isPage
};
}
public PermissionAuthorizationRequirement(string url, byte buttonType, bool isPage)
{
UrlAndButtonType = new UrlAndButtonType()
{
Url = url,
ButtonType = buttonType,
IsPage = isPage
};
}
}
/// <summary>
/// 权限过滤器
/// </summary>
[Authorize]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class PermissionAttribute : TypeFilterAttribute
{
/// <summary>
/// 构造器
/// </summary>
/// <param name="url">地址</param>
/// <param name="buttonType">按钮类型</param>
/// <param name="isPage">是否是页面</param>
public PermissionAttribute(string url = default(string), ButtonType buttonType = ButtonType.View, bool isPage = true) :
base(typeof(RequiresPermissionAttributeExecutor))
{
Arguments = new object[] { new PermissionAuthorizationRequirement(url, buttonType, isPage) };
}
/// <summary>
/// 构造器
/// </summary>
/// <param name="url">地址</param>
/// <param name="buttonType">按钮类型</param>
/// <param name="isPage">是否是页面</param>
public PermissionAttribute(string url, byte buttonType, bool isPage = true) :
base(typeof(RequiresPermissionAttributeExecutor))
{
Arguments = new object[] { new PermissionAuthorizationRequirement(url, buttonType, isPage) };
} private class RequiresPermissionAttributeExecutor : Attribute, IAsyncResourceFilter
{
private IPermissionStorageContainer _permissionStorage;
private PermissionAuthorizationRequirement _requiredPermissions; public RequiresPermissionAttributeExecutor(
IPermissionStorageContainer permissionStorage, PermissionAuthorizationRequirement requiredPermissions)
{
_permissionStorage = permissionStorage;
_requiredPermissions = requiredPermissions;
} public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
string menuUrl = _requiredPermissions.UrlAndButtonType.Url;
//判断用户权限
if (string.IsNullOrEmpty(menuUrl))
{
//区域判断
string area = context.RouteData.Values["area"].ToString();
if (string.IsNullOrEmpty(area))
{
menuUrl = "/" + context.RouteData.Values["controller"] + "/" + context.RouteData.Values["action"];
}
else
{
menuUrl = "/" + area + "/" + context.RouteData.Values["controller"] + "/" + context.RouteData.Values["action"];
}
}
menuUrl = menuUrl.Trim().ToLower();
var dbpermission = await _permissionStorage.GetPermissionAsync();
var menu = dbpermission.Menus.FirstOrDefault(m => m.MenuUrl != null && m.MenuUrl.Trim().ToLower() == menuUrl);
if (menu != null)//地址存在
{
if (_requiredPermissions.UrlAndButtonType.ButtonType == default(byte))
{
await next();
}
else
{
byte buttonType = (byte)_requiredPermissions.UrlAndButtonType.ButtonType;
if (menu.MenuButton.Select(m => m.ButtonType).Contains(buttonType))//拥有操作权限
{
await next();
}
else
{
//没有操作权限
if (_requiredPermissions.UrlAndButtonType.IsPage)
{
context.Result = new RedirectResult("/error/noauth");
}
else
{
context.Result = new ContentResult()
{
Content = PermissionStatusCodes.Status2Unauthorized.ToString()
};
}
await context.Result.ExecuteResultAsync(context);
}
}
}
else
{
//没有操作权限
if (_requiredPermissions.UrlAndButtonType.IsPage)
{
context.Result = new RedirectResult("/error/noauth");
}
else
{
context.Result = new ContentResult()
{
Content = PermissionStatusCodes.Status2Unauthorized.ToString()
};
}
await context.Result.ExecuteResultAsync(context);
}
}
} }

在对于的页面添加过滤器即可,如下:

         [HttpGet]
[Permission]
public async Task<IActionResult> Index(int pageIndex=,int pageSize=)
{
var res = await _messageService.GetPageAsync(pageIndex, pageSize);
return View(res);
}
[HttpGet]
[Permission("/Sys/Message/Index", ButtonType.View)]
public IActionResult Show()
{
return View();
}

系统界面展示图:后台模板是之前从网上找的并自己简单改了一下,将就能看吧,实在不想花功夫在前端上面了@-^-@

运行步骤:1、确保数据库mssystem和mssystemlog存在 github文档中

     2、consul服务启动,如下回车运行

     3、VS项目启动

管理员登录账号wms,密码:所有账号密码都是123

代码地址:

https://github.com/wangmaosheng/MsSystem-BPM-ServiceAndWebApps

如果觉得有点作用的话,可以 start 下,后续会持续更新

.NET Core微服务 权限系统+工作流(一)权限系统的更多相关文章

  1. .NET Core微服务 权限系统+工作流(二)工作流系统

    一.前言 接上一篇 .NET Core微服务 权限系统+工作流(一)权限系统 ,再来一发 工作流,我在接触这块开发的时候一直好奇它的实现方式,翻看各种工作流引擎代码,探究其实现方式,个人总结出来一个核 ...

  2. NET Core微服务之路:实战SkyWalking+Exceptionless体验生产环境下的追踪系统

    前言 当一个APM或一个日志中心实际部署在生产环境中时,是有点力不从心的. 比如如下场景分析的问题: 从APM上说,知道某个节点出现异常,或延迟过过高,却不能及时知道日志反馈情况,总不可能去相应的节点 ...

  3. NET Core微服务之路:实战SkyWalking+Exceptionless体验生产下追踪系统

    原文:NET Core微服务之路:实战SkyWalking+Exceptionless体验生产下追踪系统 前言 当一个APM或一个日志中心实际部署在生产环境中时,是有点力不从心的. 比如如下场景分析的 ...

  4. 【NET CORE微服务一条龙应用】第三章 认证授权与动态权限配置

    介绍 系列目录:[NET CORE微服务一条龙应用]开始篇与目录 在微服务的应用中,统一的认证授权是必不可少的组件,本文将介绍微服务中网关和子服务如何使用统一的权限认证 主要介绍内容为: 1.子服务如 ...

  5. .NET Core微服务系列基础文章索引(目录导航Final版)

    一.为啥要总结和收集这个系列? 今年从原来的Team里面被抽出来加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有 ...

  6. .NET Core微服务之基于Ocelot+IdentityServer实现统一验证与授权

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.案例结构总览 这里,假设我们有两个客户端(一个Web网站,一个移动App),他们要使用系统,需要通过API网关(这里API网关始终作为 ...

  7. .NET Core微服务系列基础文章

    今年从原来的Team里面被抽出来加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有了一个感性的认识.虽然只做了两个 ...

  8. (10)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- Ocelot+Identity Server

    用 JWT 机制实现验证的原理如下图:  认证服务器负责颁发 Token(相当于 JWT 值)和校验 Token 的合法性. 一. 相关概念 API 资源(API Resource):微博服务器接口. ...

  9. (8)学习笔记 ) ASP.NET CORE微服务 Micro-Service ---- Ocelot网关(Api GateWay)

    说到现在现有微服务的几点不足: 1) 对于在微服务体系中.和 Consul 通讯的微服务来讲,使用服务名即可访问.但是对于手 机.web 端等外部访问者仍然需要和 N 多服务器交互,需要记忆他们的服务 ...

随机推荐

  1. vim 命令总结

    命令历史 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令. 启动vim 在命令行窗口中输入以下命令即可 vim 直接启动vim vim filename 打开vim ...

  2. HOJ_14001 Just Terraffic!

    题意相对来说比较扭曲..所以来说下模型,具体做法有兴趣的孩纸去问度娘或者波塞冬吧~~ 给出一个序列长度,并且输入该序列,该序列的含义是横坐标: 任何两个相邻坐标绝对值小于等于1000的必然为一个整体, ...

  3. Android 获取地理位置信息 封装好了 直接用

    前言:花了一个早上研究了以下android获取经纬度,然后网上的参考资料都是杂七杂八,基本上都是过去几年的,现在我用 android6.0参照别人的结果发生好多错误,我的内心几乎是崩溃的.后来,不断百 ...

  4. vba中获取当前sheet页的名称,当前单元格所在位置

    fname = ActiveSheet.Name-------获取当前sheet页的名称        Sname = "" & fname & "&qu ...

  5. 用go和zk实现一个简单的分布式server

    golang的zk客户端 最近打算写个简单的配置中心,考虑到实现便捷性,语言选择了go,由于其中计划用到zk,就调研了下golang的zk客户端,并实现了个简单的分布式server.最终找到了两个,地 ...

  6. 2、HTML基础总结 part-2

    1.表单一 <html> <body> <form> 姓名: <input type="text" name="name&quo ...

  7. C 语言 习题 1-10

    练习 1-10 编写一个将输入复制到输出的程序,并将其中的制表符替换为\t,把回退符替换为\b,把反斜杠替按为\\.这样可以将制表符和回退符以可见的方式显示出来. #include<stdio. ...

  8. IOS开发学习笔记021-练习2

    只是简单练习一下,主要是学习里面的思想,处理问题的方法. 不过还有一个问题没想到解决方法. 那就是动态生成的按钮如何绑定按钮事件,请哪位大神指点一下啊.(知道怎么办了,原来是方法addTarget) ...

  9. IOS开发学习笔记010-面向对象的三大特性

    面向对象的三大特性 1.封装 2.继承 3.多态 一.封装 将类内部的属性保护起来,在外部不能直接访问,那么如果需要访问怎么办呢? OC提供了set方法来对成员变量进行访问 set方法 1.作用:提供 ...

  10. 引用其他头文件时出现这种错误,莫名其妙,error C2065: “ColorMatrix”: 未声明的标识符

    今天做项目时,直接拷贝了另一个工程里的头文件和源文件,然后运行时就出现这种问题,莫名其妙,在原程序里运行一点问题就没有,但是在新工程里就是error. >e:\c++\button_fly2\b ...