系统权限控制AOP和过滤器Filter

前言

  在后台管理项目中用户登录后,通过对权限、角色、管理员之间的分配,拥有了不同的权限集合,当用户操作不同类型的功能指令时,根据其权限集合判断该用户是否拥有该权限,如果拥有则正常使用该功能,如果没有则提示该用户没有该权限不能正常操作,因此就需要用到AOP概念以及过滤器Filter。

AOP以及过滤器概念

AOP(Aspect-Oriented Programming),面向切面编程,看着是跟OOP(面向对象编程)挺相近的,但实际上又有什么区别呢?OOP具有封装,继承,多态等东西来定义从上到下这种层次关系,但要想实现从左到右的关系的话就开始有点水土不服了,例如用户的权限控制,操作日志等,这些与我们要实现的核心功能不大有关系的东西散布在我们代码的周边,显示十分不好看。于是我们引入了AOP的模式。

Filter(过滤器)是基于AOP(面向切面编程)的设计,它的作用是对MVC框架处理客户端请求注入额外的逻辑,以非常简单优美的方式实现横切关注点(Cross-cutting Concerns)。横切关注点是指横越应该程序的多个甚至所有模块的功能,经典的横切关注点有日志记录、缓存处理、异常处理和权限验证等。Filter可以像标记属性一样用在动作、控制器上,也可以在应用在全局上,在Global.asax.cs和FilterConfig.cs中添加全局绑定。

常见的权限控制

 

权限控制流程

进入某页面执行操作==》获取该用户权限==》判断该用户所拥有的权限==》如果用户拥有进入该页面的权限则进入执行操作,否则禁止进入提示用户并为用户该权限进入

Aop(面向切面编程)

通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

AOP将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。就相当于上了一层“锁”,实现加锁和开锁。AOP是一个概念,并没有设定具体语言的实现,它能克服那些只有单继承特性语言的缺点(如Java)

生活中常见的AOP

我们通常在实现一个页面逻辑的时候,通常伴随着操作日志,安全监测,事务处理等几个逻辑,在实现逻辑的时候都要写一大堆这种代码。而AOP就是将这些与主体业务无关,但又有为业务提供服务的逻辑代码封装起来,降低模块之间的耦合度。如图所示中的圆柱体好比如我们的业务流程,AOP代表的是那个横向的操作,俗称切面编程。或许上面的这些理论有点头疼,对于AOP我的大体理解是:将那些与业务核心不大相关的杂七杂八的东西独立开,每次实现了业务核心之前或之后,调用一下对应的方法

过滤器Filter

当我们使用过滤器时,过滤器会对游览器的请求进行过滤,过滤器可以动态的分为3个部分,1.放行之前的代码,2.放行,3.放行后的代码,这3个部分分别会发挥不同作用。

第一部分代码会对游览器请求进行第一次过滤,然后继续执行
第二部分代码就是将游览器请求放行,如果还有过滤器,那么就继续交给下一个过滤器
第三部分代码就是对返回的MVC资源再次进行过滤处理

 

MVC四种过滤器

过滤器类型

实现接口

默认实现

描述

Action

IActionFilter

ActionFilterAttribute

在动作方法之前及之后运行

Result

IResultFilter

ActionFilterAttribute

在动作结果被执行之前和之后运行

AuthorizationFilter

IAuthorizationFilter

AuthorizeAttribute

首先运行,在任何其他过滤器或动作方法之前

Exception

IExceptionFilter

HandleErrorAttribute

只在另一个过滤器、动作方法、动作结果弹出异常时运行

利用过滤器实现权限控制

1、创建文件夹单独放自定义过滤器(Filters)自定义一个类( CheckMyPermissionAttribute )继承AuthorizeAttribute
2、重写OnAuthorization方法
3、获取该用户信息( filterContext.HttpContext.User as MyFormsPrincipal<LoginAdminDTO>; )
4、获取当前登录的用户权限(根据登录用户的id查询所对应的权限信息)
Userid=》user=》role=》permissions=》该用户的权限列表
注:在过滤器中调用Services时,由于当前类不是Autofac创建的,所以不会自动进行注入,所以需要手动获取Service:DependencyResolver.Current.GetService<T>()
5、判断当前的请求权限是否在用户角色所拥有的权限中,如果在则不作处理,否则返回没有权限的信息提示( filterContext.Result )
如果是执行操作类即ajax请求(filterContext.HttpContext.Request.IsAjaxRequest());则返回filterContext.Result = new JsonResult() { Data=new AjaxResult()};
否则则返回内容展示filterContext.Result = new ContentResult() { Content="" };
注:为方便标记权限添加构造函数

自定义过滤器代码

public class CheckPermissionAttribute:AuthorizeAttribute
{
public string PermissonName{get;}
public CheckPermissionAttribute(string permissonName){
    PermissonName=permissonName;
}
public override void OnAuthorization(AuthorizationContext filterContext){
    //获取当前用户登录权限
    //我们可以现获取到登录用户的ID
var user=filterContext.HttpContext.User as MyFormsPrincipal<LoginAdminDTO>;
    //user.UserData.Id
    //手动进行Service注入
IPermissionService permissionService=DependencyResolver.Current.GetService<IPermissionService >();
    //根据ID获取用户对应角色,在根据角色获取所拥有的ID
var permissions=permissionService.GetUserPermissions(user.UserData.Id);
//判断当前页面,是否在用户角色所拥有的权限中
//如果在则正常运行,否则提示报错信息
if(!permissions.Any(e=>e.Name==PermissonName)){
    //在这里需要判断用户进行的是浏览页面类还是执行操作类的行为
if(filterContext.HttpContext.Request.IsAjaxRequest()){
//如果是执行操作类的,可以根据AJAX请求,响应一个没有权限的结果
filterContext.Result=new JsonResult(){Data=new AjaxResult (AjaxResultState.Error,$"{user.UserData.Name}没有{PermissonName}权限")};
}else{
    //如果是浏览页面类行为,给出一个没有权限的提示
filterContext.Result=new ContentResult(){
Content=$"{user.UserData.Name}没有{PermissonName}权限"}";
//也可以给个跳转,跳转到没有权限的界面
}
}
}
}
自定义过滤器

过滤器限制当前用户权限代码

[HttpGet]
[CheckPermission("permission-g1")]
public ActionResult Index()
{
return View();
}
过滤器限制当前用户权限

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2022-11-06 19:00  大白白2  阅读(422)  评论(0)    收藏  举报