当前位置: 移动技术网 > IT编程>开发语言>.net > ASP.net MVC 基于角色的权限控制系统的实现

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

2018年09月21日  | 移动技术网IT编程  | 我要评论

特种兵之火凤凰63,llsibling,蒋恺老婆

、引言

 

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网