[转]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的代码如下:

代码
public IList<ActionPermission> GetAllActionByAssembly() { var result = new List<ActionPermission>();
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查询就可以了,代码如下:

复制代码
[Description("访问功能权限管理页面")] [ViewPage] public ActionResult ActionPermission() { return View(); }
复制代码

 

代码
public IList<ActionPermission> QueryActionPlist(string query, int start, int limit, out long total) { IList<ActionPermission> allActions = GetAllActionByAssembly();
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,代码如下:

代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Mvc; using System.Web; using System.Security.Principal; using Demo.HIS.Infrastructure.Facade.Authority;
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/270046.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑软件:推荐八款电脑必备效率软件

目录 1、PowerToys 微软官方效率神器 2、Ditto 剪切板神器 3、AnyTXT Searcher 文本搜索神器 4、Everything 文件检索神器 5、Monitorian 屏幕亮度调节神器 Monitorian 是一款超级实用的屏幕亮度调节工具&#xff0c;可以在任务栏以滑杆的方式调节屏幕亮度&#xff0c;且…

JVM系列(二):JVM中类加载器相关知识笔记

今天继续给大家分享JVM相关的知识&#xff0c;欢迎互相沟通交流&#xff01; 1、什么是类的加载和类的卸载 JVM虚拟机运行的文件是class文件&#xff0c;它是由我们的Java程序编译后产生的文件。 类的加载&#xff1a;JVM虚拟机将指定的class文件读取到内存里&#xff0c;并…

JVM系列(三):双亲委派机制笔记

今天给大家分享JVM系列之双亲委派机制相关的知识。 1、Java类加载的过程 Java类的加载过程是动态的&#xff0c;它不会一次性把程序所有的类全部加载后再运行&#xff0c;而是先保障程序运行的基础类加载到JVM虚拟机当中&#xff0c;其他的类&#xff0c;一般是再需要的时候才…

Python用MySQLdb, pymssql 模块通过sshtunnel连接远程数据库

安全起见&#xff0c;数据库的访问多半是要做限制的&#xff0c;所以就有一个直接的问题是&#xff0c;往往多数时候&#xff0c;在别的机器上&#xff08;比如自己本地&#xff09;&#xff0c;是不能访问数据库的&#xff0c;给日常使用造成了很大不便。所以前几天做了个需求…

运维安全:微软远程桌面修改默认远程端口

远程桌面是网络管理员必备的技能&#xff0c;今天给大家聊聊Windows本身就自带的远程桌面功能&#xff0c;如何修改远程的默认端口&#xff08;3389&#xff09;&#xff0c;让你的远程服务器更加安全。 下面给大家介绍一下如何修改远程桌面的默认端口&#xff0c;具体步骤如下…

Android Studio如何导出可供Unity使用的aar插件详解

前言 项目之前使用Eclipse导出的jar文件来做与Android交互&#xff0c;最近因为工作需要需使用Android Studio的aar文件&#xff0c;网上参考了部分文章&#xff0c;也结合自己的理解重新整理一下具体的方法&#xff0c;通过写一个测试Demo来表述Android Studio创建aar的过程与…

JVM系列(四):沙箱安全机制笔记

今天主要给大家分享JVM的沙箱安全机制笔记 1、沙箱机制的概念 Java安全模型的核心就是Java沙箱(sandbox)。 沙箱机制就是将Java代码限定只能在虚JVM虚拟机中特定的运行范围&#xff0c;并且严格限制代码对本地系统资源访问&#xff0c;通过这样的方式来保证对Java代码的有效隔…

JVM系列(五):native关键字用法介绍

今天继续给大家分享JVM中native关键字用法介绍 1、native概念 native关键字修饰的Java方法是一个原生态方法&#xff0c;方法对应的实现Java作用范围达不到&#xff0c;而是在用其他编程语言&#xff08;如C和C&#xff09;文件中实现。Java语言本身不能直接对操作系统底层进行…

ASP.NET Core 介绍和项目解读

1. 前言2. ASP.NET Core 简介 2.1 什么是ASP.NET Core2.2 ASP.NET Core的特点2.3 ASP.NET Core 项目文件夹解读 2.3.1 项目文件夹总览2.3.2 project.json和global.json2.3.1 Properties——launchSettings.json2.3.4 Startup.cs &#xff08;1&#xff09; 构造函数&#xff08…

JVM系列(六):JVM内存区域中程序计数器介绍

今天继续给大家分享JVM的相关知识&#xff0c;今天介绍一下JVM内存区域的程序计数器。 1、程序计数器概念 JVM中的程序计数寄存器&#xff08;Program Counter Register&#xff09;中Register的命名来源于CPU的寄存器&#xff0c;寄存器用来存储指令相关的现场信息。 CPU只…

JVM系列(七):虚拟机栈的相关知识介绍

今天继续给大家分享JVM系列的相关知识&#xff0c;今天介绍一下虚拟机栈的介绍。 1、虚拟机栈的概念 虚拟机栈也称为Java栈&#xff0c;Java每个main方法被执行的时候&#xff0c;JVM都会同步创建一个栈帧&#xff08;Stack Frame&#xff09;&#xff0c;通过存储局部变量表…

JVM系列(八):堆(Heap)的相关知识介绍

目录 1、JVM堆的概念 2、JVM堆的特点 3、JVM堆的内部结构 3.1 组成 3.2 堆内存内部空间所占比例 3.3 永久代和元空间区别 4、堆空间的大小设置 5、堆空间垃圾回收 1、JVM堆的概念 JVM中的堆是用来存放对象的内存空间&#xff0c;几乎所有的Java对象、数组都存储在JVM的…

电脑技巧:Hyper-V安装UOS操作系统图文教程

今天给大家分享微软官方Hyper-v虚拟机管理软件安装UOS操作系统图文教程&#xff0c;感兴趣的朋友也可以下载试一试&#xff0c;当然有啥问题也可以互相沟通交流&#xff01; 1、首先任务管理切换到性能选项卡&#xff0c;查看虚拟化是否已经启用&#xff0c;如果没有启用的话&…