ASP.net MVC 基于角色的权限控制系统的实现
我们都知道asp.net m权限控制都是实现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。你也可以用其他方式。
主要是用到了 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的用户自定义权限控制了。
上一篇: 策略模式原来这么简单!
下一篇: c语言循环语句练习题
推荐阅读
-
构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(24)-权限管理系统-将权限授权给角色
-
C#实现基于加减按钮形式控制系统音量及静音的方法
-
asp.net mvc 实现文件上传带进度条的思路与方法
-
ASP.NET MVC 主要的四种过滤器和三种具体实现类
-
基于Asp.Net Core MVC和AdminLTE的响应式管理后台之侧边栏处理
-
WebSocket在ASP.NET MVC4中的简单实现
-
Python实现的登录验证系统完整案例【基于搭建的MVC框架】
-
浅谈基于SpringBoot实现一个简单的权限控制注解
-
ASP.NET MVC实现多个按钮提交的方法
-
ASP.NET MVC 实现有论坛功能的网站(有iis发布网站