欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-07-04 12:10:39
、引言   我们都知道asp.net m权限控制都是实现authorizeattribute类的onauthorization方法。   下面是最常见的实现方式:  ...
、引言

 

我们都知道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的用户自定义权限控制了。