专栏首页JadePeng的技术博客asp.net MVC 权限设计

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 条评论
登录 后参与评论

相关文章

  • gitbook安装与使用,并使用docker部署

    本文简单介绍如何安装并使用gitbook,最后如何使用docker构建书籍镜像。 1. 前置条件 需要Nodejs环境,安装npm,国内用户再安装cnpm np...

    JadePeng
  • JavaScript 实现接口 (Interfaces In JavaScript)

    接口是面向对象编程里的重要特性,遗憾的是JavaScript并没有提供对接口的支持!怎么实现接口呢? 在实际中,我们可以在注释中定义好接口,在实际的代码中予以实...

    JadePeng
  • hugegraph 支持sparql 与cypher

    hugegraph 是百度开源的基于tinkerpop的图数据库,支持通过gremlin进行查询。

    JadePeng
  • 十六进制表示法

    一个字节由8位组成。在二进制表示法中,他的值域是00000000₂~11111111₂。如果看成十进制整数,他的值域就是0₁₀~255₁₀。两种符号表示法...

    HueiFeng
  • Python调用.net动态库实现过程解析

    cpython是分32和64位的,对应的pythonnet也是分的,版本要对应好 pythonnet最核心的就是python.Runtime.dll动态库,这...

    砸漏
  • TensorFlow强化学习入门(1.5)——上下文赌博机

    在上一篇文章中我们简要介绍了强化学习并构建了一个简单的agent来解决多臂赌博机问题。在多臂赌博机问题中agent不需要考虑所处环境的状态,只要通过学习确定那一...

    ArrayZoneYour
  • 代码防御性编程的十条技巧

    顾名思义,防御性编程是一种细致、谨慎的编程方法。为了开发可靠的软件,我们要设计系统中的每个组件,以使其尽可能的”保护”自己。我们通过明确地在代码中对设想进行检查...

    小林C语言
  • 代码防御性编程的十条技巧

    顾名思义,防御性编程是一种细致、谨慎的编程方法。为了开发可靠的软件,我们要设计系统中的每个组件,以使其尽可能的”保护”自己。我们通过明确地在代码中对设想进行检查...

    C语言与CPP编程
  • 代码防御性编程的十条技巧

    顾名思义,防御性编程是一种细致、谨慎的编程方法。为了开发可靠的软件,我们要设计系统中的每个组件,以使其尽可能的”保护”自己。我们通过明确地在代码中对设想进行检查...

    C语言与CPP编程
  • 程序员获取编程灵感的 10 种方式

    有时我会陷入读着编程书但编不了程的陷阱。我不能总是找到一个可工作的有趣项目,即使我知道有大量的机会。如果你有相同的问题,这里的一些提示可能会有所帮助。 ? 1....

    用户1289394

扫码关注云+社区

领取腾讯云代金券