asp.net MVC 权限设计

几点说明:     1、该权限系统是个网站用的,用户简单,因此不涉及到部门这些信息     2、基于将角色与controller、action相关联来判断用户是否有权     3、通过重载AuthorizeAttribute实现 数据库设计:

表说明

ControllerAction

  1.     Name是controller的名称
  2.     IsController是指是否是controller,如果为false,表示存的是action,那么controllerName字段就派上用场了
  3.     IsAllowedNoneRoles是指是否允许没有权限的人访问
  4.     IsAllowedAllRoles是指是否允许有角色的人访问

IsAllowedNoneRoles,IsAllowedAllRoles实现了允许所有人访问以及允许所有注册用户访问:),并且我们约定,IsAllowedNoneRoles具有最高的优先级,其次是IsAllowedAllRoles,然后才是ControllerActionRole中定义的规则

ControllerActionRole

 IsAllowed表示该action或者controller是否允许访问,加入表中有两条记录 角色 Name ControllName IsAllowed IsController    A Admin Home false false    A Home Null true true      这里约定分两个层次来判断权限:           第一条记录:表示A角色不能访问 Home/admin           第二条记录:表示A角色可以访问Controller下的所有方法      到底能不能访问呢?其实,我们以action为准,如果定义了action,我们直接从action的约定来判断,因此这里判断A不能访问Home/admin

 其他几张表一看就明白,不再多说

判断是否有权限的设定

    1、获取controller,action,以及存放在session中的用户信息

1 publicclass UserAuthorizeAttribute : AuthorizeAttribute 
 2     {
 3 
 4 publicoverridevoid OnAuthorization(AuthorizationContext filterContext) 
 5       { 
 6           var user = filterContext.HttpContext.Session["CurrentUser"] as User; 
 7           var controller = filterContext.RouteData.Values["controller"].ToString(); 
 8           var action = filterContext.RouteData.Values["action"].ToString(); 
 9           var isAllowed =this.IsAllowed(user, controller, action); 
10 
11 if (!isAllowed) 
12           { 
13               filterContext.RequestContext.HttpContext.Response.Write("无权访问"); 
14               filterContext.RequestContext.HttpContext.Response.End(); 
15           } 
16 
17       }
18 
19     ……
20 
21 }
22

    2、检索数据库ControllerAction表中有没有Name为第一步中controller 的记录,如果没有,我们约定这个controller是不需要进行权限控制的,如果有的话,进入第三步

   3、前面提到了,我们约定对权限的控制分为两个层次,controller和action层次,如果同时定义了,以action为准。因此,我们需要判断是否在数据库中有action的记录,如果有,进入4,无,进入5

1 bool IsAllowed(User user, string controllerName, string actionName) 
 2 { 
 3     var service = ServiceLoader.LoadService<ToySpirit.IToySpiritService.IControllerActionService>(); 
 4 
 5 // 获取对应的controller 
 6      var controller = service.GetSingleByExpression(c => c.Name == controllerName && c.IsController); 
 7 if (controller !=null) 
 8     { 
 9 // 获取对应的action 
10          var controllerAction = service.GetSingleByFunc(c => c.Name == actionName && c.IsController ==false&& c.ControllerName == controllerName); 
11 
12 return controllerAction ==null?this.isAllowed(user, controller) : this.isAllowed(user, controllerAction); 
13     } 
14 
15 // 没有定义controller的权限,表示无需权限控制 
16  returntrue; 
17 }
18 
19

4、如果有action的记录,那么我们首先判断controllerAction 拒绝哪些角色访问,如果用户有角色在这里面,很遗憾,就不能访问了;然后判断controllerAction 允许哪些角色访问,如果用户的角色在这里面,就可以访问了

注:这里很有可能用户有多个角色,比如A,B,C,如果A不能访问controllerAction,那么很遗憾,用户不能访问,尽管角色B,C可能可以访问该controllerAction

5、没有action的记录,自然就检查controller对应的controllerAction 了

代码
4、5判断的代码是一样的,如下:
      privatebool isAllowed(User user, ControllerAction controllerAction) 
        { 
            // 允许没有角色的:也就是说允许所有人,包括没有登录的用户 
if (controllerAction.IsAllowedNoneRoles) 
            { 
                returntrue; 
            } 
            // 允许所有角色:只要有角色,就可以访问 
if (controllerAction.IsAllowedAllRoles) 
            { 
                return user.Roles.Count >0; 
            } 
            if (user ==null|| user.Roles.Count ==0) 
            { 
                returnfalse; 
            } 
            // 选出action对应的角色 
            var roles = controllerAction.ControllerActionRoles.Select(ca => ca.Role).ToList(); 
            if (roles.Count ==0) 
            { 
                // 角色数量为0,也就是说没有定义访问规则,默认允许访问 
returntrue; 
            } 
            var userHavedRolesids = user.Roles.Select(r => r.ID).ToList(); 
            // 查找禁止的角色 
            var notAllowedRoles = controllerAction.ControllerActionRoles.FindAll(r => r.IsAllowed ==false).Select(ca => ca.Role).ToList(); 
            if (notAllowedRoles.Count >0) 
            { 
                foreach (Role role in notAllowedRoles) 
                { 
                    // 用户的角色在禁止访问列表中,不允许访问 
if (userHavedRolesids.Contains(role.ID)) 
                    { 
                        returnfalse; 
                    } 
                } 
            } 
            // 查找允许访问的角色列表 
            var allowRoles = controllerAction.ControllerActionRoles.FindAll(r => r.IsAllowed).Select(ca => ca.Role).ToList(); 
            if (allowRoles.Count >0) 
            { 
                foreach (Role role in allowRoles) 
                { 
                    // 用户的角色在访问的角色列表 
if (userHavedRolesids.Contains(role.ID)) 
                    { 
                        returntrue; 
                    } 
                } 
            } 
            returnfalse; 
        }

使用方法:

建立一个basecontroller,使用我们定义好的UserAuthorize,然后所有的controller继承basecontroller就可以了

1 ///<summary> 
2 /// 控制基类 
3 ///</summary>
4     [UserAuthorize] 
5 publicabstractclass BaseController : Controller 
6    {}
7 
8 publicclass HomeController : BaseController{}
9

演示:

在controlleraction中添加几条数据:

根据我们的规则,我们可以知道,未登录的用户可以访问Home/Public,其他几个页面则不能访问

我们看对应的Action:

1 publicvoid ViewPage() 
 2        { 
 3            Response.Write("View"); 
 4        } 
 5 publicvoid Public() 
 6        { 
 7            Response.Write("Public"); 
 8        } 
 9 publicvoid Delete() 
10        { 
11            Response.Write("Delete"); 
12        }

访问Home/Public,如果有权限,那么显示“Public“,否则显示”无权访问”

未登录用户访问Home/Public,结果符合我们的约定;-)

未登录用户访问Home/ViewPage,按约定应该显示错误信息

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏LeoXu的博客

Tapestry 教程(七)在Tapestry中一起使用Hibernate

好了,你填写了所有的输入域,提交了这个表单(没有任何验证错误),瞧:你又回到了相同的表单,所有的格子里面都是空的。发生了什么,数据都到哪儿去了?

483
来自专栏专注研发

PageHelper分页插件及通用分页js

物理分页依赖的是某一物理实体,这个物理实体就是数据库,比如MySQL数据库提供了limit关键字,程序员只需要编写带有limit关键字的SQL语句,数据库返回的...

841
来自专栏Golang语言社区

golang go-sql-drive mysql连接池的实现

golang内部自带了连接池功能,刚开始接触golang的时候不了解这个,还自己搞了一个 sql.Open的对象管理池,真的非常囧啊。 sql.Open函数实际...

8614
来自专栏电光石火

php JSON格式化

php 的json_encode能把数组转换为json格式的字符串。字符串没有缩进,中文会转为unicode编码,例如\u975a\u4ed4。人阅读比较困...

854
来自专栏Golang语言社区

十条有用的 Golang语言 技术

十条有用的 Go 技术 这里是我过去几年中编写的大量 Go 代码的经验总结而来的自己的最佳实践。我相信它们具有弹性的。这里的弹性是指: 某个应用需要适配一个灵...

4059
来自专栏coder修行路

Go实现海量日志收集系统(三)

1493
来自专栏技术之路

[原创翻译]Protocol Buffer Basics: C#

Protocol Buffer 基础知识:c#    原文地址:https://developers.google.com/protocol-buffers/d...

2029
来自专栏青枫的专栏

day59_BOS项目_11

第一步:创建一个流程实例管理ProcessInstanceAction,提供list()方法,查询流程实例列表数据

893
来自专栏腾讯移动品质中心TMQ的专栏

结合静态代码扫描来给插件间接口把把脉

如火如荼的EP建设中小鹅收到了一个小小的需求,如何知道每个版本变更了哪些插件间接口呢,有没有及时覆盖?

1966
来自专栏精讲JAVA

深入探索 Java 热部署

在 Java 开发领域,热部署一直是一个难以解决的问题,目前的 Java 虚拟机只能实现方法体的修改热部署,对于整个类的结构修改,仍然需要重启虚拟机,对类重新加...

581

扫码关注云+社区