在程序复杂程度不断上升的过程中,无可避免需要触碰到权限控制,而权限控制又与业务逻辑紧紧相关,市场上出现了大量的权限控制产品,而程序的开发,讲究去繁化简的抽象,在我的开发过程中,逐渐发现程序的权限控制核心不外乎两个方面: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. Pyinstaller 中 pandas出错问题的解决(详细)

    环境配置 pip install pyinstaller pyinstaller中的参数 -F 表示生成单个可执行文件 -c 显示命令行窗口,一般一开始的时候使用,如果没有错误,那就使用-w命令 -w ...

  2. C++小结:迟到的小结和重新起航的故事

    迟到的小结和重新起航的故事 有关这个学期的故事,随着这个学期的结束也划上了一个句号. 正如之前博客里面(还是空间里面)提到的,在这个过程中的收获比最后考试的结果更重要. 就像这次的计算器,也许会对最后 ...

  3. UVa 815 洪水!

    https://vjudge.net/problem/UVA-815 题意:一个n*m的方格区域,共有n*m个方格,每个方格是边长为10米的正方形,整个区域的外围是无限高的高墙,给出这n*m个方格的初 ...

  4. ros rviz 启动指定的rviz 文件

    rviz -d rviz文件名 例如:rviz -d myname.rviz

  5. Mac OS下 selenium 驱动safari日志

    /Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home/bin/java "-javaagent:/Applicat ...

  6. JavaScript的知识基本介绍

    ECMAScript js简单介绍(与java的区别)        1.语法(区分大小写,弱类型,分号可写可不写)        2.变量(只能使用var定义,要么不定义,如果在函数内部使用var定 ...

  7. linux 系统调用号表

    位于 /usr/include/asm/unistd.h 由于我是64位系统,所以有一些额外的东西.我的这个文件为下文 #ifndef _ASM_X86_UNISTD_H #define _ASM_X ...

  8. typescripts学习

    可选与默认参数 可选参数:在参数名后面,冒号前面添加一个问号,则表明该参数是可选的.如下代码: function buildName(firstName: string, lastName?: str ...

  9. English trip -- MC(情景课)3 C Do you have a sister?

    xu言:   学了困难的在去看以前的课程,发现真的容易多了.So 学习的最好方法和提速方式,那就是找困难的不断去挑战.尝试.尝试.在尝试! Grmmar ['græmə]  focus  ['fəʊk ...

  10. EF学习-获取实体框架01

    实体框架由 EF 设计器(包含在 Visual Studio 中)和 EF Runtime(在 NuGet 上提供)组成. EF 设计器包含在 Visual Studio 中 最新版本的实体框架设计器 ...