基于资源名的MVC权限控制
在程序复杂程度不断上升的过程中,无可避免需要触碰到权限控制,而权限控制又与业务逻辑紧紧相关,市场上出现了大量的权限控制产品,而程序的开发,讲究去繁化简的抽象,在我的开发过程中,逐渐发现程序的权限控制核心不外乎两个方面: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权限控制的更多相关文章
- 基于Vue实现后台系统权限控制
原文地址:http://refined-x.com/2017/08/29/基于Vue实现后台系统权限控制/,转载请注明出处. 用Vue/React这类双向绑定框架做后台系统再适合不过,后台系统相比普通 ...
- 利用基于@AspectJ的AOP实现权限控制
一. AOP与@AspectJ AOP 是 Aspect Oriented Programming 的缩写,意思是面向方面的编程.我们在系统开发中可以提取出很多共性的东西作为一个 Aspect,可以理 ...
- 基于RESTful API 设计用户权限控制
RESTful简述 本文是基于RESTful描述的,需要你对这个有初步的了解. RESTful是什么? Representational State Transfer,简称REST,是Roy Fiel ...
- asp.net core mvc权限控制:分配权限
前面的文章介绍了如何进行权限控制,即访问控制器或者方法的时候,要求当前用户必须具备特定的权限,但是如何在程序中进行权限的分配呢?下面就介绍下如何利用Microsoft.AspNetCore.Ident ...
- ASP.NET MVC权限控制思路
在系统开发的时候一个老生常谈的权限管理问题,翻阅了很多的网络资料,但是总感觉离实际使用还有一段距离,其实权限控制无非就几个“请求.页面按钮.字段显示”, 对于前端权限就需要配合JS了, 这里主要展示我 ...
- Laravel 5 中间件、路由群组、子域名路由、 权限控制的基本使用方法
创建控制器: php artisan make:controller Admin/IndexController 创建Middleware: php artisan make:middleware T ...
- .NET MVC权限控制
一.模块 权限控制的主体单位,与MVC里的Cotroller相对应. 二.模块权限 权限控制的最小单位,通过给每一个模块设置权限,可以控制到非常细小的功能. 三.角色 权限拥有者,通过给不同的角色分配 ...
- asp.net core mvc权限控制:权限控制介绍
在进行业务软件开发的时候,都会涉及到权限控制的问题,asp.net core mvc提供了相关特性. 在具体介绍使用方法前,我们需要先了解几个概念: 1,claim:英文翻译过来是声明的意思,一个cl ...
- asp.net core mvc权限控制:在视图中控制操作权限
在asp.net core mvc中提供了权限验证框架,前面的文章中已经介绍了如何进行权限控制配置,权限配置好后,权限验证逻辑自动就会执行,但是在某些情况下,我们可能需要在代码里或者视图中通过手工方式 ...
随机推荐
- ajax post 参数说明
- ajax用beforeSend自定义请求过程中客户端事件,提高用户体验
本文为博主原创,未经允许不得转载: 在应用ajax的过程中,当我们再前台提交请求的时候,如果服务端响应事件比较长,就会导致需要等很长时间在前台才能接受到服务端返回的 响应结果,往往会导致用户重复点击按 ...
- CSU 1808 地铁(最短路变形)
http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1808 题意: Bobo 居住在大城市 ICPCCamp. ICPCCamp 有 n 个地铁站, ...
- # WinForm关闭窗体确认
private void Lba_IE_Form_FormClosing(object sender, FormClosingEventArgs e) { if (MessageBox.Show(&q ...
- BZOJ 2339 【HNOI2011】 卡农
题目链接:卡农 听说这道题是经典题? 首先明确一下题意(我在这里纠结了好久):有\(n\)个数,要求你选出\(m\)个不同的子集,使得每个数都出现了偶数次.无先后顺序. 这道题就是一道数学题.显然我们 ...
- 安装cartographer_ros
这里使用的是hitcm(张明明)的github地址,由于google官方的教程需要FQ下载一些文件,因此容易失败,经验证hitcm(张明明)对原文件进行了少许修改后可以成功安装,在他的修改中核心代码不 ...
- F4+2 团队项目软件设计方案
目录 1引言 1.1编写目的 1.2背景 1.3定义 1.4参考资料 2总体设计 2.1需求规定 2.2运行环境 2.3基本设计概念和处理流程 2.4功能描述 2.5功能器求与程序的关系 2.6人工处 ...
- js 中的 堆栈
1.含义及对比 堆和栈都是运行时内存中分配的一个数据区,因此也被称为堆区和栈区: 二者存储的数据类型和处理速度不同: 堆(heap)用于复杂数据类型(引用类型)分配空间,例如数组对象.object对象 ...
- 算法笔记--sg函数详解及其模板
算法笔记 参考资料:https://wenku.baidu.com/view/25540742a8956bec0975e3a8.html sg函数大神详解:http://blog.csdn.net/l ...
- web前端设计规范
hi,这里写出一点自己对web产品开发的一点粗浅的规范认识,一切为了敏捷开发哈哈. 1.流程. (1) 当产品给出原型和产品文档. (2)设计师更据原型,开始设计产品的效果图. (3)设计师设计完毕后 ...