说起php的权限,很多人都容易想起rbac,这里不多介绍。下面介绍一种通用的权限设计:
首先我们设定一种场景,我们为一个商城做了一个权限系统,商城里有许多店铺,每个店铺有店长和店员,商城还有运营助理帮忙管理这些店铺。
一、基础表:
店铺表,这里只取店铺的id和name。
菜单表,这里取每个菜单的 模块/控制器/方法 和名称,
角色表,主要用在分配角色的时候,我们约定,level越低权限等级越高,权限分配的时候,只能由高等级向下分配。比如:店长可以给
店员分配权限,但是不能给运营助理和其他店长分配权限。运营助理可以给店长和店员分配权限。
二、权限分配
权限分配的界面如上图,这个没什么好说的。
权限分配时,主要要解决的问题是,当前用户能给哪些用户分配哪些权限。我们这里的设计是:
1、当前用户只能给等级比自己低(level大于自己)的人分配权限;
2、当前用户只能给权限范围比自己小或者相同的人分配权限,比如,2号店的店长只能为2号店的店员分配权限,不能给1号店的店员分配
3、当前用户只能分配自己有的权限,比如,2号店长只有订单管理的权限,那他只能分配订单管理这个菜单给店员,不能分配会员信息给
店员,同理,负责2号3号店的运营助理只能分配2号店给某店长,不能分配1号店给某店长。
上图是一个分配结果。用户1是运营助理,负责1号2号店铺,有1到3所有的菜单的权限。用户2是2号店店长,有1到3菜单的权限。
Ⅰ、创建权限:
这时我们登陆用户2,现在如果要新建用户,那么只能建level大于3的用户,即店员。建立好用户后,要给这个用户分配权限,那么
店铺只能分配店铺2,菜单可以从当前用户有的1,2,3中选择任意组合的菜单。
同时,如果我们登陆用户1,我们既可以新建店长也可以新建店员,比如这时候没有1号店的店长,那我们新建一个店长,负责1号店,
同时给他操作1-3菜单的权限。
如上图,我们新建的两个用户。
Ⅱ、修改权限:
和创建的规则相同,如果我们登陆用户2,用户2可以修改用户3的权限,但是他不能修改用户3的店铺,只能修改用户3的菜单权限(rule),
比如从1,2,修改成2,3。
但是如果我们登陆用户1,他就可以修改用户2-4的权限,比如他可以修改用户3的store到1,菜单不变,那么此时用户3就是1号店的店员了。
三、权限验证
权限创建好了,接下来就是如何验证权限了。
Ⅰ、结果显示:
所谓结果显示,就是当前用户只能看到当前用户有权限的菜单。比如,上表中的3号用户,他只能看到菜单1和2,同时,菜单1是会员信息,那么
他只能看到2号店铺的会员信息。这个很简单,只需要数据库关联查询就可以了。但是在这里我建议,单独封装一个方法来获取用户的权限。
这样的好处就是修改的时候可以统一修改。比如我这里有个fuction,就是从数据库把rule取出来。但是如果需求改变了,不准任何用户操作1号菜
单。那么这时候你只需要在这个function里把结果中的1去掉就好了,而不需要每个地方都去改。
Ⅱ、权限验证:
结果显示只能说防君子不防小人,因为就算你隐藏了,也可以通过url来访问。比如你的url /store/store_id/1 表示访问1号店铺,这时候,就算你的在界面上
隐藏了2号店铺,但是我依旧可以通过 /store/store_id/2访问。所以权限控制需要在控制器里进行拦截。这时候一般是把权限验证放在基类的构造函数中。
phper要注意php不会主动执行父类构造函数的问题,然后其他的控制器继承这个基类(基础控制器)。
那么在用户访问一个方法的时候,首先验证这个用户是否有访问当前方法的权限,有则通过,没有则报错。例如上表中的用户3,他有访问菜单1和2的
权限,也就是Admin/Base/member和Admin/Base/order。那此时他访问Admin/Base/goods方法,就应该到报错界面。
同样,我们规定对店铺的访问key必须是store_id,那么就可以获取store_id的参数,如果是2,则用户3可以访问,反之如果是其他的,则报错。同样,
我们统一商品的必须用good_id表示,那么我们获取good_id的id,如果他属于店铺2,则用户3可以访问,反之拒绝。
以上,一个简单的B2B2C的权限系统就完成了,当然,权限系统一般都和具体的业务和需求结合得比较紧密,大家在实际设计时可以进行相应的限制或者
拓展。