在程序复杂程度不断上升的过程中,无可避免需要触碰到权限控制,而权限控制又与业务逻辑紧紧相关,市场上出现了大量的权限控制产品,而程序的开发,讲究去繁化简的抽象,在我的开发过程中,逐渐发现程序的权限控制核心不外乎两个方面:1、资源定位;2、访问控制列表。本文主要针对资源定位进行分析,并解决一些我所遇见过的问题。而在MVC上,MVC提供给我们了非常好的访问控制扩展机制,我们能够通过这些机制更好地控制系统权限。

  在我们之前的开发中,针对ASP.NET下WebForm进行开发,很多人都采用了继承Page基类自定义BasePage,构造自己的验证逻辑后再将最终的展示页面继承于BasePage,所有的验证逻辑中,也必须解决我上文中提到的两个问题:资源定位和访问控制列表。而WebForm下使用路由机制的机会并不多,意义也并不大,在这个背景下,大多数人产生了这样的错觉:使用URL进行资源定位就够了。我所见过的几个项目,大多采用了这个办法,或者这个办法的细微变种。而WebForm的机制也决定了这个方法是具有一定可行性的,每一个资源(页面)都是一个类,资源定位较为容易。而进入MVC时代后,一切都发生了改变。在MVC的场景下,你将遇到以下几个问题:

  1、  路由机制的引入会出现一个资源多个URL的可能以及增加Area等参数后URL的不确定性。

  2、  Action重载的问题难以解决。例如一个页面Order,在Get方法下不带参访问是被允许的,而在Post下带参访问是被禁止的,但这两个资源的URL都是 /Order/,在一些第三方库的辅助下,甚至能有更多的重载Action,这就导致URL定位机制的全面失效。

  而面对上述情况,用一种什么样的方式进行资源的定位、控制就成为放在我们面前的难题。在MVC下,可以认为每一个方法(Action)即为一个资源(页面),用何种方法能在程序外部控制这些资源使得权限控制能对其轻松进行,这是整个问题的核心。上文说到,每个方法即为一个资源,那我们是否可以将方法名、方法签名作为资源的定位标识?答案是可以的。

  在MVC下,进行权限控制,很自然地想到了使用自定义AuthorizationFilter来进行控制,那么在这个Attribute中是可以获得方法相关信息的。

var t = (ReflectedActionDescriptor) filterContext.ActionDescriptor;
var method= t.MethodInfo.ToString();

  在派生自FilterAttribute, IAuthorizationFilter的自定义Attribute中,可以根据上面两个方法获取方法的完整签名,包括返回类型、方法名、参数类型。

  通过这个方法是可以进行权限控制的,但是这个方法存在着一个致命的缺点:返回值的类型名、参数的类型名,有的是完全限定名,即需要带命名空间,而有的是不完全限定名。而这个完全限定名的获取是较为繁琐的,因此,这个方法的可操作性大大降低。

  那如何优雅地定位到我们所需要控制的资源呢?我们是否可以为我们所需要的资源取一个名字,然后在访问控制列表中将这个名字添加进去,每次执行这个Action的时候获取当前Action的名字,然后在访问控制列表中进行比对就可以解决这个问题。那如何将资源进行命名就成了解决问题的关键。代码级的资源控制必须想到元数据,而需要在元数据中增加信息,这个任务自然又落到Attribute的身上。

  我们自定义一个Attribute为Action标注资源名称:

  [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class ResourceCustomerNameAttribute : Attribute
{
private readonly string _resourceName; public ResourceCustomerNameAttribute(string resourceName)
{
_resourceName = resourceName;
} public string ResourceName
{
get { return _resourceName; }
}
}

  这个Attribute实现的功能很简单:为资源进行命名(如果方便,使用ID会更高效一点)。

  完成了对资源的命名,接下来需要对资源与访问控制列表进行比对,我是这样使用的:继承FilterAttribute, IAuthorizationFilter,在派生类中先获取ResourceCustomerNameAttribute实例

  然后用attribute.ResourceName属性与我们的访问控制列表进行比对:

    public void OnAuthorization(AuthorizationContext filterContext)
{
var acl = filterContext.HttpContext.Session[SessionName.PermissionSessionName] as IEnumerable<IAcl>; var attNames = filterContext.ActionDescriptor.GetCustomAttributes(typeof(ResourceCustomerNameAttribute), true) as IEnumerable<ResourceCustomerNameAttribute>; var anonymous =filterContext.ActionDescriptor.GetCustomAttributes(typeof(AllowAnonymousAttribute), true) as IEnumerable<AllowAnonymousAttribute>; if (anonymous != null && anonymous.Any())
{
return;
}
if (acl == null || !acl.Any())
{
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Controller = _controller, action = _action }));
}
else
{
var joinResult = (from aclEntity in acl
join attName in attNames on aclEntity.ResourceName equals attName.ResourceName
select attName
).Any(); if (joinResult)
{
return;
}
else
{
filterContext.Result = new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary(new { Controller = _controller, action = _action }));
}
}
}

  如果比对成功则获取相应访问许可,可以对资源进行访问,若比对失败则跳转至授权失败页面。

  而在实际的使用过程中,我们在登录成功后,将构造用户的ACL,并将ACL存入Session中,之后用户在每一次的访问中均使用Session中的ACL进行比对,授权。

  在这个具体实现中,我有一个难以处理的问题:即用户访问页面时若未授权,则跳转到未授权提示页面,若用户进行基于Json传递的ajax调用时如何向用户提供合适的信息?之前考虑过使用ContentType来判断,可是后来觉得这会导致开发之中的约定过多(更何况我对很多人对Http协议的了解程度并不抱有信心)。不知各位是否有更好的办法来实现多种错误返回信息?望不吝赐教。

  模块的具体代码已托管于GitHub:https://github.com/uliian/ULiiAnPermissionControlModule

  功能核心模块已经上传,示例正被GFW狂虐~各位稍安勿躁,如有靠谱的全局科学上网方法的同学也希望悄悄告诉我一下~T.T

  欢迎参考,提出您的宝贵意见。

基于资源名的MVC权限控制的更多相关文章

  1. 基于Vue实现后台系统权限控制

    原文地址:http://refined-x.com/2017/08/29/基于Vue实现后台系统权限控制/,转载请注明出处. 用Vue/React这类双向绑定框架做后台系统再适合不过,后台系统相比普通 ...

  2. 利用基于@AspectJ的AOP实现权限控制

    一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理 ...

  3. 基于RESTful API 设计用户权限控制

    RESTful简述 本文是基于RESTful描述的,需要你对这个有初步的了解. RESTful是什么? Representational State Transfer,简称REST,是Roy Fiel ...

  4. asp.net core mvc权限控制:分配权限

    前面的文章介绍了如何进行权限控制,即访问控制器或者方法的时候,要求当前用户必须具备特定的权限,但是如何在程序中进行权限的分配呢?下面就介绍下如何利用Microsoft.AspNetCore.Ident ...

  5. ASP.NET MVC权限控制思路

    在系统开发的时候一个老生常谈的权限管理问题,翻阅了很多的网络资料,但是总感觉离实际使用还有一段距离,其实权限控制无非就几个“请求.页面按钮.字段显示”, 对于前端权限就需要配合JS了, 这里主要展示我 ...

  6. Laravel 5 中间件、路由群组、子域名路由、 权限控制的基本使用方法

    创建控制器: php artisan make:controller Admin/IndexController 创建Middleware: php artisan make:middleware T ...

  7. .NET MVC权限控制

    一.模块 权限控制的主体单位,与MVC里的Cotroller相对应. 二.模块权限 权限控制的最小单位,通过给每一个模块设置权限,可以控制到非常细小的功能. 三.角色 权限拥有者,通过给不同的角色分配 ...

  8. asp.net core mvc权限控制:权限控制介绍

    在进行业务软件开发的时候,都会涉及到权限控制的问题,asp.net core mvc提供了相关特性. 在具体介绍使用方法前,我们需要先了解几个概念: 1,claim:英文翻译过来是声明的意思,一个cl ...

  9. asp.net core mvc权限控制:在视图中控制操作权限

    在asp.net core mvc中提供了权限验证框架,前面的文章中已经介绍了如何进行权限控制配置,权限配置好后,权限验证逻辑自动就会执行,但是在某些情况下,我们可能需要在代码里或者视图中通过手工方式 ...

随机推荐

  1. 51nod 1086 背包问题 V2

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1086 思路  裸的多重背包 巩固一下刚学的骚操作 #include< ...

  2. Linux下指定pip install和make install安装路径

    在Linux下直接用pip install packageName,有些文件会被放到根目录下,如果没有sudo权限的话,是会安装失败的.这个以后我们就需要指定安装的目录了. pip install - ...

  3. [Err] 1111 - Invalid use of group function

    本文为博主原创,未经允许不得转载: 初衷,本想通过group by sql语句查询出不同id下总数在一定范围内的数据,所以产生如下的sql,及错误sql AND STATDATE < ' GRO ...

  4. Codeforces Round #323 (Div. 2) C. GCD Table map

    题目链接:http://codeforces.com/contest/583/problem/C C. GCD Table time limit per test 2 seconds memory l ...

  5. hdu 3579 Hello Kiki 不互质的中国剩余定理

    Hello Kiki Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Probl ...

  6. http post发送请求

    一: 用java自带URL发送 public synchronized JSONObject getJSON(String url2, String param) { try { URL url = ...

  7. Hadoop 部分截图

  8. 磁条卡,IC卡,ID卡,信用卡芯片卡,信用卡磁条卡 等等的区别

    1.条码卡:该卡卡面上有一串条码,通过扫描枪或者相应的条码读卡器读出该条码卡的卡号.根据条码的不同又分为39码等其它码.条码卡仅仅是一个编号,不存蓄其它内容.特点:价格便宜类似磁卡. 2.磁条卡:类似 ...

  9. Windows 上安装 MySQL

    Windows 上安装 MySQL https://www.mysql.com/downloads/ 1.下载MySQL安装包(官网下载链接): 选择 DOWNLOADS ——> Communi ...

  10. PL/SQL Developer-官网下载地址

    官网下载地址:https://www.allroundautomations.com/registered/plsqldev.html