ASP.net MVC 基于角色的权限控制系统的实现

一、引言

我们都知道ASP.net mvc权限控制都是实现AuthorizeAttribute类的OnAuthorization方法

下面是最常见的实现方式:

 public class CustomAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
           if (!filterContext.RequestContext.HttpContext.Request.IsAuthenticated)
            {
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "account", action = "login", returnUrl = filterContext.HttpContext.Request.Url, returnMessage = "您无权查看." }));
                return;
            }
          base.OnAuthorization(filterContext);
        }
}

然后在需要验证的Action上打上[CustomAuthorize]标签就可以了。

这种方式是比较粗粒度的解决方案,由于是已经将定义好(约定好的)权限hard code带对应的Action上,所以无法实现用户自定义权限控制。

看一下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Deepleo.Role.Controllers
{
    public class UserController : Controller
    {
        [UserAuthorize]
        public ActionResult Index()
        {
            return View();
        }
       [AdminAuthorize]
        public ActionResult Admin()
        {
            return View();
        }
        [UserAuthorize]
        public ActionResult Detail()
        {
            return View();
        }
    }
}

我们有一个UserController,他有3个Action:Index,Admin,Detail.其中Admin需要系统管理员权限,其他两个值需要User权限。这样就需要建立AdminAuthorizeAttributeUserAuthorizeAttribute.这样做就无法实现用户自定义权限。

二、基于角色的权限控制系统

基于角色的权限控制系统RBAC(Role Based Access Control)是目前最流行,也是最通用的权限控制系统。

对于ASP.NET MVC来说,这套系统很容易实现:Controller下的每一个Action可以看作是一个权限,角色就相当于多个权限的组合。

然后我们新建一个RoleAuthorizeAttribute,即对角色的属性描述。

2.1 如何鉴权

这个RoleAuthorizeAttribute的关键在于如何拿到ControllerName和ActionName,查阅msdn其实很容易就实现了,不多说,直接上代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.Mvc;
using System.Web.Routing;
using Deepleo.Role.Services;

namespace Deepleo.Role.Attributes
{
    public class RoleAuthorizeAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var isAuth = false;
            if (!filterContext.RequestContext.HttpContext.Request.IsAuthenticated)
            {
                isAuth = false;
            }
            else
            {
                if (filterContext.RequestContext.HttpContext.User.Identity != null)
                {
                    var roleService = new RoleService();
                    var actionDescriptor = filterContext.ActionDescriptor;
                    var controllerDescriptor = actionDescriptor.ControllerDescriptor;
                    var controller = controllerDescriptor.ControllerName;
                    var action = actionDescriptor.ActionName;
                    var ticket = (filterContext.RequestContext.HttpContext.User.Identity as FormsIdentity).Ticket;
                    var role = roleService.GetById(ticket.Version);
                    if (role != null)
                    {
                        isAuth = role.Permissions.Any(x => x.Permission.Controller.ToLower() == controller.ToLower() && x.Permission.Action.ToLower() == action.ToLower());
                    }
                }
            }
            if (!isAuth)
            {
                filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "account", action = "login", returnUrl = filterContext.HttpContext.Request.Url, returnMessage = "您无权查看." }));
                return;
            }
            else
            {
                base.OnAuthorization(filterContext);
            }
        }
    }
}

注意:这里用Ticket的Version存储RoleId。你也可以用其他方式。

主要是用到了 filterContext.ActionDescriptor和filterContext.ActionDescriptor。

2.2 如何生成权限控制列表

前面的role.Permissions的集合已经是定义好的权限列表。

Permissions类的定义如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Deepleo.Role.Entities
{
    public class PermissionDefinition
    {
        public virtual int Id
        {
            set;
            get;
        }
        public virtual int ActionNo
        {
            set;
            get;
        }

        public virtual int ControllerNo
        {
            set;
            get;
        }
        public virtual string Name
        {
            set;
            get;
        }

        public virtual string ControllerName
        {
            set;
            get;
        }
        public virtual string Controller
        {
            set;
            get;
        }
        public virtual string Action
        {
            set;
            get;
        }
        public virtual DateTime AddDate
        {
            set;
            get;
        }
    }
}

属性Controller和Action记录的是权限,ControllerName和ActionName用于显示UI,ControllerNo和ActionNo用于显示顺序控制。

这里你可以手工将所有Action录入数据库中,然后实现RolService即可。但是显然这种方法实在是太笨了,我们其实可以用反射+Attribute机制实现自动化载入权限控制表。原理很简单,我就直接上关键代码了。

以下是反射的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Deepleo.Role.Services;
using Deepleo.Role.Attributes;
using Deepleo.Role.Entities;

namespace Deepleo.Role.Controllers
{
    public class InstallController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index()
        {
            try
            {
                var roleService = new RoleService();
                #region init permission
                createPermission(new UserController());
                #endregion

                var allDefinedPermissions = roleService.GetDefinedPermissions();
                #region 超级管理员角色初始化
                var adminPermissions = new List<RolePermissionInfo>();
                foreach (var d in allDefinedPermissions)
                {
                    adminPermissions.Add(new RolePermissionInfo { AddDate = DateTime.Now, Permission = d, });
                }
                int adminRoleId = roleService.AddRole(new Entities.RoleInfo
                {
                    AddDate = DateTime.Now,
                    Description = "",
                    Name = "超级管理员",
                    Permissions = adminPermissions
                });
                #endregion
                return RedirectToAction("Admin", "User");
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.Message);
                return View();
            }
        }
        private void createPermission(Controller customController)
        {
            var roleService = new RoleService();

            var controllerName = "";
            var controller = ""; var controllerNo = 0;
            var actionName = ""; var action = ""; var actionNo = 0;
            var controllerDesc = new KeyValuePair<string, int>();

            var controllerType = customController.GetType();
            controller = controllerType.Name.Replace("Controller", "");//remobe controller posfix
            controllerDesc = getdesc(controllerType);
            if (!string.IsNullOrEmpty(controllerDesc.Key))
            {
                controllerName = controllerDesc.Key;
                controllerNo = controllerDesc.Value;
                foreach (var m in controllerType.GetMethods())
                {
                    var mDesc = getPropertyDesc(m);
                    if (string.IsNullOrEmpty(mDesc.Key)) continue;
                    action = m.Name;
                    actionName = mDesc.Key;
                    actionNo = mDesc.Value;
                    roleService.CreatePermissions(actionNo, controllerNo, actionName, controllerName, controller, action);
                }
            }
        }
        private KeyValuePair<string, int> getdesc(Type type)
        {
            var descriptionAttribute = (DescriptionAttribute)(type.GetCustomAttributes(false).FirstOrDefault(x => x is DescriptionAttribute));
            if (descriptionAttribute == null) return new KeyValuePair<string, int>();
            return new KeyValuePair<string, int>(descriptionAttribute.Name, descriptionAttribute.No);
        }
        private KeyValuePair<string, int> getPropertyDesc(System.Reflection.MethodInfo type)
        {
            var descriptionAttribute = (DescriptionAttribute)(type.GetCustomAttributes(false).FirstOrDefault(x => x is DescriptionAttribute));
            if (descriptionAttribute == null) return new KeyValuePair<string, int>();
            return new KeyValuePair<string, int>(descriptionAttribute.Name, descriptionAttribute.No);
        }
    }
}

以下是DescriptionAttribute的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Deepleo.Role.Attributes
{
    public class DescriptionAttribute : Attribute
    {
        public string Name
        {
            set;
            get;
        }
        public int No
        {
            set;
            get;
        }
    }
}

然后在UserController打上DescriptionAttribute标签就可以了,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Deepleo.Role.Attributes;

namespace Deepleo.Role.Controllers
{
    [Description(No = 1, Name = "用户")]
    public class UserController : Controller
    {
        [RoleAuthorize]
        [Description(No = 1, Name = "用户首页")]
        public ActionResult Index()
        {
            return View();
        }
        [RoleAuthorize]
        [Description(No = 1, Name = "用户管理")]
        public ActionResult Admin()
        {
            return View();
        }
        [RoleAuthorize]
        [Description(No = 1, Name = "用户详情")]
        public ActionResult Detail()
        {
            return View();
        }
    }
}

这样在网站安装的时候直接执行Install就可以完全自动化创建权限。

这样就可以精确到每个Action的用户自定义权限控制了。

看看我的劳动成果:

写在最后:对于同名的Action的HttpGET和HttpPOST分成两个权限还没有实现。比如说:New[HttpGet],和New[HttpPOST]。主要是觉得这样没有太大的意义,当然如果你的业务需求必须这样,我觉得应该很容易就能扩展。

完整代码下载:http://files.cnblogs.com/deepleo/RoleSolution.rar

PS:代码只有关键代码,没有实现RoleService方法,请自行根据自己的实际情况实现。

ASP.net MVC 基于角色的权限控制系统的实现

时间: 2024-11-06 03:52:08

ASP.net MVC 基于角色的权限控制系统的实现的相关文章

ASP.NET MVC 基于角色的权限控制系统的示例教程

上一次在 .NET MVC 用户权限管理示例教程中讲解了ASP.NET MVC 通过AuthorizeAttribute类的OnAuthorization方法讲解了粗粒度控制权限的方法,接下来讲解基于角色的权限控制方法. 基于角色的权限控制方法概述 基于角色的权限控制系统RBAC(Role Based Access Control)是目前最流行,也是最通用的权限控制系统.所谓基于角色的权限控制,就是将各个操作权限分组,每一个组就是一个角色,举个例子:管理员拥有所有的权限,编辑就只拥有写文章和发布

基于角色的权限访问控制初步

基于角色的权限访问控制(Role-Based Access Control) 角色访问控制(RBAC)引入了role的概念,目的是为了隔离user(即动作主体,subject)与privilege(权限,表示对resource的一个操作,即operation+resource).role作为一个用户(user)与权限(privilege)的代理层,解耦了权限和用户的关系,所有的授权应该给予role而不是直接给user或 group.privilege是权限颗粒,由operation和resour

基于角色的权限管理系统

我们开发业务系统的时候,基本上都会涉及到权限管理模块,要求不同的人看到不同的菜单,操作不同的按钮,看到不同的数据.很多初学者面对这样的需求不知道如何下手,特别是稍微复杂点的权限,更是找不到方向,为此我们夜鹰教程网特别推出了这套基于角色的权限管理视频教程,通过给用户分配角色,给角色分配权限,来实现权限管理.这样一来,可以实现不同的人管理不同的菜单,操作不同的按钮,看到不同的数据.可以划分权限组,每个组的成员拥有相同的权限.也可以把同一个人分配到不同的权限组,具有多个权限组的权限,实现权限的组合.

从零开始——基于角色的权限管理01(补充)

此博文较为详细的介绍从零开始--基于角色的权限管理01文中的两个部分的流程(解释代码). 1) index.jsp中提交跳转action action的login,获取jsp页面传过来的用户名密码和验证码,进行验证 首先到userDao中,执行login方法,判断是否存在这组用户名和密码 接着到roleDao中,执行getRoleNameById以获取角色名 最后,进入main.jsp中 2)在main.jsp中,有一个树的显示,再次进入authServlet中执行menuAction   先后

基于角色的权限控制

首先要明白的有一个表就是需要记录整个项目中控制器和方法,这样在权限检测的时候就可以检测数据库对应的角色有没有这个控制器或者方法的权限, 但是需要明白的是在开发的过程中当然需要把这种权限给取消,这样在开发过程是需要增加一个控制器或者方法就不需要验证权限,然后开发好了之后就需要 在权限表中增加该控制器和方法. 一般基于角色的权限控制,需要用到下面的几张表 1.用户表2,权限表,3.角色表,4权限角色关系表5用户角色关系表 这种方式是用户通过,用户角色关系表查询出自己的角色,然后通过权限角色关系表查出

使用Lync 2013 基于角色的权限控制:RBAC 给用户分配指定的操作权限

使用场景: 在大型的Lync统一沟通系统的日常运维中,我们需要为不同角色的管理员分配不同的Lync管理权限,在Lync Server 2013上面就使用了基于角色的权限控制:RBAC ,它里面分了多种权限角色,包括 CsAdministrator,CsUserAdministrator,CsVoiceAdministrator,CsServerAdministrator,CsViewOnlyAdministrator,CsHelpDesk等等,不同的角色有不同的Lync管理权限, 例如,当我们只

ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上

原文:ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上 ASP.NET MVC默认采用基于标准特性的Model验证机制,但是只有应用在Model类型及其属性上的ValidationAttribute才有效.如果我们能够将ValidationAttribute特性直接应用到参数上,我们不但可以实现简单类型(比如int.double等)数据的Model验证,还能够实现“一个Model类型,多种验证规则”,本篇文章将为你提供相关的解决方案(源代码

ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则

原文:ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则 对于Model验证,理想的设计应该是场景驱动的,而不是Model(类型)驱动的,也就是对于同一个Model对象,在不同的使用场景中可能具有不同的验证规则.举个简单的例子,对于一个表示应聘者的数据对象来说,针对应聘的岗位不同,肯定对应聘者的年龄.性别.专业技能等方面有不同的要求.但是ASP.NET MVC的Model验证确是Model驱动的,因为验证规则以验证特性的形式应用到Model类型及其属性上.这样的验证

基于角色的权限设计(一)

在任何系统中,权限设计是最基础的东西,本文给出一个基于角色的权限设计的循序渐进的设计方案. 在权限系统中,功能(权限)是最小的单位,比如起草新闻.编辑新闻.审核新闻.删除新闻等,而角色是一类功能的集合,比如新闻编辑 这个角色,他可能有起草新闻.编辑新闻等功能集合,而责任编辑他可能就有更多的权限,比如除了新闻编辑的功能,还有审核新闻.删除新闻等功能,给张三赋予 新闻编辑的角色(其实我更愿意说把张三加入到新闻编辑这个角色中去),张三就可以起草新闻.编辑新闻了,给李四赋予责任编辑的角色,李四就可以起草