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权限。这样就需要建立AdminAuthorizeAttribute和UserAuthorizeAttribute.这样做就无法实现用户自定义权限。
二、基于角色的权限控制系统
基于角色的权限控制系统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(最好不要这样,原因看我的另一篇博文:http://www.cnblogs.com/deepleo/p/iso_cookies_formsAuthenticationTicket_version.html)。你也可以用其他方式。
主要是用到了 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 = ;
var actionName = ""; var action = ""; var actionNo = ;
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 = , Name = "用户")]
public class UserController : Controller
{
[RoleAuthorize]
[Description(No = , Name = "用户首页")]
public ActionResult Index()
{
return View();
}
[RoleAuthorize]
[Description(No = , Name = "用户管理")]
public ActionResult Admin()
{
return View();
}
[RoleAuthorize]
[Description(No = , 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 基于角色的权限控制系统的实现的更多相关文章
- ASP.NET MVC 基于角色的权限控制系统的示例教程
上一次在 .NET MVC 用户权限管理示例教程中讲解了ASP.NET MVC 通过AuthorizeAttribute类的OnAuthorization方法讲解了粗粒度控制权限的方法,接下来讲解基于 ...
- 基于角色的权限控制系统(role-based access control)
role-based access control(rbac),指对于不同角色的用户,拥有不同的权限 .用户对应一个角色,一个角色拥有若干权限,形成用户-角色-权限的关系,如下图所示.当一个用户进行访 ...
- ASP.NET MVC 基于页面的权限管理
菜单表 namespace AspNetMvcAuthDemo1.Models { public class PermissionItem { public int ID { set; get; } ...
- MVC基于角色权限控制--数据库设计
在网站后台设计过程中都会遇上权限控制这一问题 当前较为流行的解决方案是基于角色的权限管理 基本思路如下 分别建立 用户信息表.角色信息表.权限信息表 让用户和角色关联,角色和权限关联,当用户访问时,通 ...
- Asp.net core IdentityServer4与传统基于角色的权限系统的集成
写在前面 因为最近在忙别的,好久没水文了 今天来水一篇: 在学习或者做权限系统技术选型的过程中,经常有朋友有这样的疑问 : "IdentityServer4的能不能做到与传统基于角色的权限系 ...
- FineAdmin.Mvc 使用ok-admin+ASP.NET MVC搭建的通用权限后台管理系统
FineAdmin.Mvc 介绍 使用ok-admin+ASP.NET MVC搭建的通用权限后台管理系统RightControl后台layui模板不太好看,换成ok-admin v2.0重写一遍.项目 ...
- ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上
原文:ASP.NET MVC基于标注特性的Model验证:将ValidationAttribute应用到参数上 ASP.NET MVC默认采用基于标准特性的Model验证机制,但是只有应用在Model ...
- ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则
原文:ASP.NET MVC基于标注特性的Model验证:一个Model,多种验证规则 对于Model验证,理想的设计应该是场景驱动的,而不是Model(类型)驱动的,也就是对于同一个Model对象, ...
- C 实现基于角色的权限系统
本文demo下载地址:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=1068 实例使用C# 实现基于角色的权限 ...
随机推荐
- Ubuntu下禁用笔记本自带键盘
想要禁用笔记本自带键盘(Ubuntu)只要2条命令. 1. 打开终端,输入: xinput list ⎡ Virtual core pointer id=2 [master pointer (3)] ...
- Oracle 监听/数据库 启动/关闭
LSNRCTL命令启动.关闭和查看监听器的状态的方法 从lsnrctl status命令的输出中得到监听器状态,包括如下的信息: 监听器的启动时间 监听器的运行时间 监听器参数文件listener.o ...
- 我与0xc000007b奋斗的日子
自从新换了一台笔记本,就开始重装各种软件,就在将要开始软工课设的重要的日子里,我默默地在运行客户端时出现了一个这样的错误: 鉴于本人很废柴,自然不可能去查内存,所以开始各种度娘必应和谷歌,哦!原来应该 ...
- jQuery Ajax(load,post,get,ajax)
1.load(url, [data], [callback]) 载入远程 HTML 文件代码并插入至 DOM 中. 默认使用 GET 方式 - 传递附加参数时自动转换为 POST 方式.jQuery ...
- PHP与web 页面交互
PHP与Web页面交互是实现PHP网站与用户交互的重要手段.在PHP中提供了两种与Web页面交互的方法,一种是通过Web表单提交数据,另一种是通过URL参数传递. 这里我们将详细讲解表单的相关知识,为 ...
- 【bzoj3809/bzoj3236】Gty的二逼妹子序列/[Ahoi2013]作业 莫队算法+分块
原文地址:http://www.cnblogs.com/GXZlegend/p/6805252.html bzoj3809 题目描述 Autumn和Bakser又在研究Gty的妹子序列了!但他们遇到了 ...
- [洛谷P2216][HAOI2007]理想的正方形
题目大意:有一个$a\times b$的矩阵,求一个$n\times n$的矩阵,使该区域中的极差最小. 题解:二维$ST$表,每一个点试一下是不是左上角就行了 卡点:1.用了一份考试时候写的二维$S ...
- [GDOI2016] 疯狂动物园 [树链剖分+可持久化线段树]
题面 太长了,而且解释的不清楚,我来给个简化版的题意: 给定一棵$n$个点的数,每个点有点权,你需要实现以下$m$个操作 操作1,把$x$到$y$的路径上的所有点的权值都加上$delta$,并且更新一 ...
- eclipse增加jar包方式对比
add external jars = 增加工程外部的包add jars = 增加工程内包add library = 增加一个库add class folder = 增加一个类文件夹 add jar ...
- poj 3678 Katu Puzzle 2-SAT 建图入门
Description Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a ...