zoukankan      html  css  js  c++  java
  • 权限设计

    我们在开发系统的时候,经常会遇到系统需要权限控制,而权限的控制程度不同有不同的设计方案。

     

    1.       基于角色的权限设计

    这种方案是最常见也是比较简单的方案,不过通常有这种设计已经够了,所以微软就设计出这种方案的通用做法,这种方案对于每一个操作不做控制,只是在程序中根据角色对是否具有操作的权限进行控制;这里我们就不做详述

    2.       基于操作的权限设计

    这种模式下每一个操作都在数据库中有记录,用户是否拥有该操作的权限也在数据库中有记录,结构如下:


    但是如果直接使用上面的设计,会导致数据库中的
    UserAction这张表数据量非常大,所以我们需要进一步设计提高效率,请看方案3

     

    3.       基于角色和操作的权限设计


    如上图所示,我们在添加了
    Role,和RoleAction表,这样子就可以减少UserAction中的记录,并且使设计更灵活一点。

    但 是这种方案在用户需求的考验之下也可能显得不够灵活够用,例如当用户要求临时给某位普通员工某操作权限时,我们就需要新增加一种新的用户角色,但是这种用 户角色是不必要的,因为它只是一种临时的角色,如果添加一种角色还需要在收回此普通员工权限时删除此角色,我们需要设计一种更合适的结构来满足用户对权限 设置的要求。

     

    4.       2,3组合的权限设计,其结构如下:


    我们可以看到在上图中添加了
    UserAction表,使用此表来添加特殊用户的权限,改表中有一个字段HasPermission可以决定用户是否有某种操作的权限,改表中记录的权限的优先级要高于UserRole中记录的用户权限。这样在应用程序中我们就需要通过UserRoleUserAction两张表中的记录判断权限。

    到这儿呢并不算完,有可能用户还会给出这样的需求:对于某一种action所操作的对象某一些记录会有权限,而对于其他的记录没有权限,比如说一个内容管理系统,对于某一些频道某个用户有修改的权限,而对于另外一些频道没有修改的权限,这时候我们需要设计更复杂的权限机制。

     

    5.       对于同一种实体(资源)用户可以对一部分记录有权限,而对于另外一些记录没有权限的权限设计:


    对于这样的需求我们就需要对每一种不同的资源创建一张权限表,在上图中对
    ContentChannel两种资源分别创建了UserActionContentUserActionChannel表用来定义用户对某条记录是否有权限;这种设计是可以满足用户需求的但是不是很经济,UserActionChannelUserActionContent中的记录会很多,而在实际的应用中并非需要记录所有的记录的权限信息,有时候可能只是一种规则,比如说对于根Channel什么级别的人有权限;这时候呢我们就可以定义些规则来判断用户权限,下面就是这种设计。

     

    6.       涉及资源,权限和规则的权限设计


    在这种设计下角色的概念已经没有了,只需要
    Rule在程序中的类中定义用户是否有操作某种对象的权限。

    以上只是分析思路,如果有不对的地方,请大家指正。
















    在任何系统中,权限设计是最基础的东西,本文给出一个基于角色的权限设计的循序渐进的设计方案。

      在权限系统中,功能(权限)是最小的单位,比如起草新闻、编辑新闻、审核新闻、删除新闻等,而角色是一类功能的集合,比如新闻编辑 这个角色,他可能有起草新闻、编辑新闻等功能集合,而责任编辑他可能就有更多的权限,比如除了新闻编辑的功能,还有审核新闻、删除新闻等功能,给张三赋予 新闻编辑的角色(其实我更愿意说把张三加入到新闻编辑这个角色中去),张三就可以起草新闻、编辑新闻了,给李四赋予责任编辑的角色,李四就可以起草新闻、 编辑新闻、审核新闻、删除新闻了。

      我们来看看版本一的解决方案:


     

      我们来模拟一下上面的数据:

      用户信息表:

    UserID

    UserName

    U1

    张三

    U2

    李四

      角色表:

    RoleID

    RoleName

    R1

    新闻编辑

    R2

    责任编辑

      角色用户表:

    RoleID

    UserID

    R1

    U1

    R2

    U2

      功能表:

    FunctionID

    FunctionName

    F1

    起草新闻

    F2

    编辑新闻

    F3

    审核新闻

    F4

    删除新闻

      角色功能表:

    RoleID

    FunctionID

    R1

    F1

    R1

    F2

    R2

    F1

    R2

    F2

    R2

    F3

    R2

    F4

      我们来看看如何判断一个用户具有某个功能权限:

      首先在用户张三登录的时候,获取张三的全部功能列表:

    Select FunctionID From 角色功能表 Where RoleID In (Select RoleID From 用户角色表 Where UserID=’U1’)

      这样就可以得到张三的全部功能列表Functions,在起草新闻的页面我们就可以做如下判断:

    Functions.Contain(‘F1’);//当然你可以把这个’F1’定义成一个常量:NewsFunction.Draft

      如果为true就说明张三有起草新闻的权限。

      当然对于web应用,您可以把Functions session保存起来,以避免每打开一个页面都去数据库中获取。

      似乎看起来是一个不错的解决方案。

      还是新闻系统,最初新闻系统没有分类,但是随着新闻的增加,没有分类的新闻看起来总是乱的,于是张三和李四给新闻添加了分类A、分类B,还是由张三负责起草,李四负责审核,以后又添加了更多的分类,并且也增加了人手,这个时候就有新的要求出来了:希望张三只负责分类A的起草,分类B的起草交给其他人做,李四呢也只负责分类A的审核(就相当于是一个栏目的责任编辑)。

     
    样的需求,版本一就无能为力了(当然你也可以增加几个功能:比如分类A的新闻起草和分类B的新闻起草,再把这个功能添加到相应的角色里面去,但是这个应该不是我们要得解决方案吧,不过版本二也是基于这个思想来解决的)。

    其实比新闻更好的例子是论坛板块的版主。

    下面是版本二的解决方案:


    在版本二的功能表中加入了一个
    ResourceType这个字段,这个字段用来表示对某个资源的分类(比如新闻),我们同样来模拟一下(新闻分类AResourceType为:NTA,分类B为:NTB):

    功能表:

    FunctionID

    ResourceType

    FunctionName

    F1

    NTA

    起草新闻:分类A

    F2

    NTA

    编辑新闻:分类A

    F3

    NTA

    审核新闻:分类A

    F4

    NTA

    删除新闻:分类A

    F1

    NTB

    起草新闻:分类B

    F2

    NTB

    编辑新闻:分类B

    F3

    NTB

    审核新闻:分类B

    F4

    NTB

    删除新闻:分类B

    然后在角色表添加相应的角色,在角色功能表中添加对应的功能。

    获取Functions的语句也相应地做变化:

    Select FunctionID  + ‘,’ + ResourceType From 角色功能表 Where RoleID In (Select RoleID From 用户角色表 Where UserID=’U1’)

    权限的判断也就变成:

    Functions.Contain(‘F1,NTA’);

    在新添加一个分类的时候,同时也在功能表中增加相应的记录(当然不是在数据库里面直接添加,由和功能相关的函数来添加)。

    使用这种解决方案可以简单地对有分类的应用(比如论坛系统)的每个分类实行不同的控制(比如VIP板块,就只能拥有VIP角色的用户才能浏览、发表等,而其他板块只要是注册用户就可以使用了)。

    在实际应用中FunctionID并不是随便的一个字符串,而是进行了编码,其编码中包含了模块ID以及能够体现出父子关系,举个例子来说:对于论坛系统,我们给它一个模块ID”30”,论坛的功能我们先分成2类,一类是管理类(比如删除帖子),一类是使用类(比如发帖、回帖、浏览帖子等),给管理类一个编码:01,使用类一个编码:02,我们就对FunctionID进行如下的编码:

    300101:删除帖子

    300201:发帖

    300202:回帖

    300203:浏览帖子

    对于资源(比如某个板块1,板块的ID为:01),我们可以组合出如下的Functions(当然这个组合你也可以不用逗号分隔,用其他的组合方式也可以,不过不要产生歧义):

    300101,01:板块1删除帖子的功能

    300201,01:板块1发帖的功能

    ……

        对于RoleID也是采用的编码方式,也能体现角色的父子关系,也可以实现角色功能的继承等(当然获取角色功能列表的SQL语句就不是现在这么简单了)。在我现在的应用里面没有实现角色的继承(虽然角色的编码体现出了角色的父子关系)。

  • 相关阅读:
    贰、js的基础(二)类型转换
    贰、js的基础(一)
    ajax的异步请求小结
    壹、js的概述
    sass的用法小结(四)进阶篇
    sass的用法小结(三)
    sass的用法小结(二)
    sass的用法小结(一)
    H5页面在线制作工具搜集
    H5教程:移动页面性能优化
  • 原文地址:https://www.cnblogs.com/smallfa/p/1103459.html
Copyright © 2011-2022 走看看