授权系统几乎所有业务系统都会用到,所以可以单独开一章来讲。
授权的原理
每个用户拥有一系列“权限”,用户在登录之后,访问页面/接口,系统会根据登录用户查询其权限列表,检查是否具有访问目标页面/接口的权限。如果有访问权限,则访问成功,如果没有访问权限,则弹出提示“没有访问权限”。
授权系统可以分为基于用户的授权
、基于角色的授权
、基于用户或者角色的授权
。下面分别讲一下。
基于用户的授权
基于用户的授权最简单,一张用户表,一张用户权限表。
用户表:存储用户信息
用户权限表:存储用户id和权限
举个栗子,用户表
有一条记录为“Lulu”,id为1。在用户权限表
中添加一条记录,用户id为1,权限为“GetData”。则用户Lulu拥有了“GetData”的权限。
她是怎么拥有权限的呢?当然不是存在数据库里面就完事了。在调用需要“GetData”权限的“GetDataApi”接口的时候,在访问GetDataApi之前,通过程序,查询登录用户Lulu的权限列表,查询到了“GetData”权限,Lulu就通过了权限验证。如图所示:
按照授权的原理,上述是最简单的方式,用户直接拥有权限。
也可以设计成一张用户表
,一张权限表
,一张用户权限表
。因为用户可以拥有多个权限,同一权限也可以被多个用户拥有,用户和权限是多对多
的关系。在设计成用户表-用户权限表-权限表时,权限的内容,比如“GetData”存储在权限表,用户权限表仅存储用户id和权限id,作为二者之间的中间表
。如图所示:
基于用户的授权可以实现授权的基本需求,但是存在一些麻烦的问题:比如一个小区的安保问题,每个保安应该有100个权限,包括小区大门、各单元大门、防火栓等地方的门禁——好嘛,每次有保安入职,都要为他配置这100个权限,还不能勾错,这不是折腾人么!再想想,因为某些现实原因,需要临时开启或关闭某个地方的门禁,所以我们需要给每个保安重新配置这个权限,真是满满的工作量啊!
我们似乎需要有一个可以抽象出保安群体,为他们统一配置权限
的东西,这就是第二种授权方式——基于角色的授权
。
基于角色的授权
这种方式我们引入一个新的概念“角色”
。我们不再单独为某个用户发放权限,而是给角色配置权限,再把用户和角色匹配起来。
继续小区的话题,我们将所有保安的权限,用“保安角色”进行统一管理,为“保安角色”配置权限,而将每个保安与“保安角色”挂钩,则每个保安会获得“保安角色”所拥有的权限。说起来似乎有些饶,直接看图!
我们需要一张用户表,一张角色表,一张用户角色表,一张角色权限表。像这样:
如此,我们想要新增、删除某个保安的权限,只需要修改用户角色表
。我们想要修改“保安角色”的权限,只需要修改角色权限表
。
需要注意的是,用户、角色必须是一对多的关系,比如一个保安既可能是安保人员,也可能是“主任”这种管理人员,则他应该拥有“保安”和“主任”两种角色都有的权限。
当然,我们也可以基于“基于用户的授权”的第二种方式,把角色-权限
这部分拆的更细:
基于角色的授权是一种比较好的实现授权的方式,但它似乎不够灵活。想一想,在销售行业,同一职级的工作者,也可以有不同范围的权限。在“基于角色的授权”中,我们只能通过创建两个角色“XX职级角色1”和“XX职级角色2”来实现——很丑,对不对,而且如果这个行业需要更加灵活的权限配置
,“基于角色的授权”似乎不能满足需求。
那我们就回归“基于用户的授权”?想想就觉得不科学,这时候就可以出现一种结合上述二者,取其精华去其糟粕的方式了——基于用户或者角色的授权
。
基于用户或者角色的授权
在这种授权方式下,我们既可以通过“用户”去授权,也可以通过“角色”去授权。
所以我们可以通过“角色”为用户配置具有普遍性的权限,而通过“角色授权”为个别特殊用户单独授权。
如此,来解决统一授权和特殊授权的问题。
我们需要一张用户表,一张角色表,一张用户角色表,一张用户/角色权限表。
如图所示,保安1拥有“保安角色”的所有权限,同时拥有特殊权限“特殊门门禁权限”,而保安2仅拥有“保安角色”的权限。
当然,我们依然像之前一样,可以把角色-权限
这部分拆分出来.
如何选择
一句话,“根据业务”,还有个人习惯,当然要灵活可变,肯定还是选择基于用户或者角色的授权
。
以上只是比较普遍的授权系统设计方式,根据具体需求的不同,可能还需要进行新的设计,这也是计算机的魅力所在。同一份问卷,不同的人也可以交出不同的解答,当然它们都是非常优雅的解答:)