[转]Asp.Net大型项目实践(11)-基于MVC Action粒度的权限管理【续】【源码在这里】(在线demo,全部源码)...
本文转自:http://www.cnblogs.com/legendxian/archive/2010/01/25/1655551.html
接上篇Asp.Net大型项目实践(10)-基于MVC Action粒度的权限管理(在线demo,全部源码)
在线Demo:
地址:http://218.60.8.35:1234/
服务器:网通
端口:不要禁用1234端口应该就可以访问
注意:连了数据库的,时间仓促肯定有漏洞,不要捣乱哈:)
登录用户: 1.用户名:牛头人战士 密码:000000 权限:有全部菜单页面,不能进行数据库的更改操作(不影响录入体验)
2.用户名:老虎MM 密码:000000 权限:少两个菜单页面,不能进行数据库的更改操作(不影响录入体验)
3.用户名:admin 密码不公开 权限:所有权限
注:以上的实现都是通过权限管理s配置出的哈,没有任何硬编码
权限判断的边界
由于项目是基于MVC的,除去数据权限不说,功能权限的判断边界做在MVC 的Action上无疑是最好的选择,因为无论是一个页面,还是一个按钮,还是一次查询,都是通过Action请求实现的。这样我们只需要在每个Action请求执行之前进行权限判断就可以了,也不用折腾RBAC里的资源+操作=权限 这么麻烦。
菜单权限和功能权限
其实在MIS项目中,大多数的权限判断粒度还是页面级的,再加上我们还需要根据权限动态生成用户的菜单,所以我们把权限分成“菜单权限”和“功能权限”
菜单权限:在用户登录验证后,每个页面的请求都必须通过权限验证。
功能权限:默认客户进入页面后,页面的相关操作默认都不判断,只对显示维护出的功能权限进行权限判断。
这样有几个好处:一般情况下权限的配置简单了,因为只需要配置粗粒度的页面权限即可使用;增加了效率,不必每个Action执行之前都判断权限(虽然都做了缓存,但能少判断一次还是好的);完全不影响细粒度的权限判断,随时都可以增加对任何一个Action的权限判定
如何取Action功能权限
我们通过反射把所有的Action权限全部取出来,这样在维护选取的时候就比较方便了,也不会产生录入错误,如下图:
大家用Demo可以体验到我们模糊输入Action名称就可以找到我们想要的Action的,因为是配置选取用也不用担心什么反射的效率问题,其实大家从demo可以看到速度还是挺快的,在我真实的项目中Action中有上万个,拉出来一样是瞬时的,所以我觉得有时候吧,也别过于“谈反射色变”,呵呵
通过反射获取所有Action的代码如下:
var types = Assembly.Load("Demo.HIS.MVC").GetTypes();
foreach (var type in types) { if (type.BaseType.Name == "BaseController")//如果是Controller { var members = type.GetMethods(); foreach (var member in members) { if (member.ReturnType.Name == "ActionResult")//如果是Action {
var ap = new ActionPermission();
ap.ActionName = member.Name; ap.ControllerName = member.DeclaringType.Name.Substring(0, member.DeclaringType.Name.Length - 10); // 去掉“Controller”后缀 object[] attrs = member.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), true); if (attrs.Length > 0) ap.Description = (attrs[0] as System.ComponentModel.DescriptionAttribute).Description;
result.Add(ap); }
} } } return result; }
返回的IList<ActionPermission>就是系统中所有Action的集合,大家可看到我们通过BaseController找到了项目中所有的Controller,再通过ActionResult找到Controller中所有的Action。
不知道大家注意下拉出的Action有个描述属性,这个属性是通过在Action上定义DescriptionAttribute实现的,这样通过反射就能取到中文描述了,例如:为了实现页面的选取方便,我们还要实现对IList<ActionPermission>的分页和模糊查询,因为是变量级集合,这里我们使用Linq查询就可以了,代码如下:
total = (from a in allActions where a.ActionName.ToLower().Contains(query.ToLower()) select a).Count();
var result = (from a in allActions where a.ActionName.ToLower().Contains(query.ToLower()) select a).Skip(start).Take(limit);
return new List<ActionPermission>(result); }
把权限判断相关的数据都缓存起来提高效率
我们把当前登录用户的:用户信息,拥有菜单权限,拥有功能权限 放在Session里
我们把需要托管的所有Action功能权限放在 Appliction全局应用程序变量里
这样我们所有的权限相关判断都是从缓存中取数据,不需要频繁访问数据了。
相关代码懒得贴了,自己去下载的源码里翻吧....注意一下缓存相关都是通过ICache这个接口出的,搜一下就能找到
如何对每个Action进行拦截,在它执行之前判断权限
最土的办法就是在每个Action加一段权限判断的代码,哈哈...如果我要这样做的话,估计要被大家的砖头拍死。
看过本系列Asp.Net大型项目实践(7)-用Unity实现AOP之事务处理+为啥要用AOP(附源码)的朋友应该就能想到,这是一个典型的AOP应用场景。
由于Asp.net MVC的Filter机制其实就是Aop,所以我们直接使用它。熟悉Asp.net MVC的朋友估计知道里面其实自带的有一个AuthorizeAttribute的ActionFilter,但基本就是个玩具,本来我想继承它重写的,但无奈里面的filterContext没有ActionDescriptor属性,所以干脆不要它自己写个ActionFilter,代码如下:
namespace Demo.HIS.MVC.CommonSupport.Filter { /// <summary> /// 权限拦截 /// </summary> [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class AuthorizeFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext == null) { throw new ArgumentNullException("filterContext"); } var path = filterContext.HttpContext.Request.Path.ToLower(); if (path == "/" || path == "/Main/Login".ToLower() || path == "/Main/UserLogin".ToLower()) return;//忽略对Login登录页的权限判定 object[] attrs = filterContext.ActionDescriptor.GetCustomAttributes(typeof(ViewPageAttribute), true); var isViewPage = attrs.Length == 1;//当前Action请求是否为具体的功能页 if (this.AuthorizeCore(filterContext, isViewPage) == false)//根据验证判断进行处理 { //注:如果未登录直接在URL输入功能权限地址提示不是很友好;如果登录后输入未维护的功能权限地址,那么也可以访问,这个可能会有安全问题 if (isViewPage == true) { filterContext.Result = new HttpUnauthorizedResult();//直接URL输入的页面地址跳转到登陆页 } else { filterContext.Result = new ContentResult { Content = @"JsHelper.ShowError('抱歉,你不具有当前操作的权限!')" };//功能权限弹出提示框 } } } //权限判断业务逻辑 protected virtual bool AuthorizeCore(ActionExecutingContext filterContext, bool isViewPage) { if (filterContext.HttpContext == null) { throw new ArgumentNullException("httpContext"); }
if (!filterContext.HttpContext.User.Identity.IsAuthenticated) { return false;//判定用户是否登录 } var user = new CurrentUser();//获取当前用户信息 var controllerName = filterContext.RouteData.Values["controller"].ToString(); var actionName = filterContext.RouteData.Values["action"].ToString(); if (isViewPage && (controllerName.ToLower() != "main" && actionName.ToLower() != "masterpage"))//如果当前Action请求为具体的功能页并且不是MasterPage页 { if (user.MenuPermission.Count(m => m.ControllerName == controllerName && m.ActionName ==
转载于:https://www.cnblogs.com/freeliver54/p/6385001.html
[转]Asp.Net大型项目实践(11)-基于MVC Action粒度的权限管理【续】【源码在这里】(在线demo,全部源码)...相关推荐
- Asp.Net大型项目实践系列导航 [以后要仔细看的,支持作者 转]
关键字 NHibernate,ExtJs,Asp.Net MVC,Unity,业务领域驱动DDD,SOA,WCF,WF,分层开发,权限管理,异常管理,事务管理,日志管理... 宣传语 这里没有无聊的口 ...
- [转载](asp.net大型项目实践)
首先感谢:传说中的弦哥http://www.cnblogs.com/legendxian/ 关键词::NHibinate,Json,SOA,大型三甲医院信息管理系统.------ 医院信息系统(Hos ...
- Asp.Net大型项目实践(7)-用Unity实现AOP之事务处理+为啥要用AOP(附源码)
在目录中我计划对权限管理,异常管理,事务管理,日志管理,异常管理等项目中AOP典型应用场景进行详细的描述,本篇我们用Unity的Interception来实现项目中的事务处理. 为啥要用AOP 由于这 ...
- angular大型项目实践总结的几个要点
angular大型项目实践总结的要点 整理电脑文档,顺便搬用到博客,文字是2018年写的 国际化要提前做,贯穿整个开发过程 图标,图片,规范化,使用统一的方式使用,无论是雪碧图还是字体化(有很多把图片 ...
- 简洁的MobX与MVP思想—大型项目实践
很久之前想写一篇对Redux的研究,但是网上写的很多,而MobX相比较Redux更小众,网上很多资料例如介绍api的都是官网的复刻节选,而我用MobX感觉真的很爽,所以写篇文章帮助初入MobX坑的玩家 ...
- 基于角色的访问控制'的权限管理的数据库的设计实现
RBAC基于角色的访问控制的权限管理系统数据库设计与实现 use [master] go -- 检查数据库 [RBAC]是否存在,如果存在则删除(只测试用,不然会丢数据.) -- Search fro ...
- 基于MVC轻量级的JWT权限验证
简单的JWT验证框架 JWT就不多介绍了 传统的shiro和SpringSecurity安全框架需要Session,重启后Session会丢失,或者将Session存入redis也行,但是相对比较繁琐 ...
- 基于吉日嘎拉的通用权限管理Webform版老界面bug修复
虽然弄了新界面<基于吉日嘎底层架构的通用权限管理Web端UI更新:参考DTcms后台界面>,但老界面的一点菜单显示的问题还是让我这种强迫症揪心,终于今晚可以美美的睡觉了. 老代码用了Ses ...
- 大数据项目实践:基于hadoop+spark+mongodb+mysql开发医院临床知识库系统
一.前言 从20世纪90年代数字化医院概念提出到至今的20多年时间,数字化医院(Digital Hospital)在国内各大医院飞速的普及推广发展,并取得骄人成绩.不但有数字化医院管理信息系统(HIS ...
最新文章
- php先分组后排序,PHP数组分组排序实例代码
- 实用精美的导航条制作
- linux 快捷matlab_Linux命令 笔记(一)
- Linux下一些实用的操作记录
- 跳表(SkipList)设计与实现(java)
- Object 标签遮挡 Div 显示
- windows 2008 R2下安装Exchange 2010(单域环境下)
- Jackson用法详解
- 【转】onAttachedToWindow()在整个Activity生命周期的位置及使用
- android 实体对象转 json,list转 json ,map转json
- SQL Server添加Northwind数据库
- 7-24 约分最简分式 (15 分)
- 做什么样的软件才能赚钱?
- golang not enough arguments in call to uuid.Must have (uuid.UUID) want (uuid.UUID, error)
- Python-day11~13-前端初步
- Linux 启动定时任务配置
- L1-概率论中的10个基本概念:古典概率、联合概率、条件概率、生日问题等
- java ssi_java SSI idea
- rust最美建筑_[资料整理]动物之森的美丽物语 (多图;补完)
- linux服务器引导分区,Linux系统的引导过程和磁盘分区信息