PHP项目实践 RBAC权限管理
基本概念
RBAC(Role-Based Access Control,基于角色的访问控制),用户通过角色与权限进行关联。
一个用户可以拥有多个角色,每个角色拥有若干个权限,每个权限对应相关操作行为,实现“用户(User)-角色(Role)-权限(Rule)-行为(Action)”的授权模型。
实体关系如下:
项目需求
- 系统管理员拥有最大权限,管理所有企业账户;
- 每个企业有一个企业管理员,拥有企业所有权限,可以分配管理企业子账户;
- 企业子账户根据企业管理员分配权限限定操作权限。
所以权限层级应该是:运营管理员>企业管理员>企业子账户
表的设计
- 用户表 user
- id 用户标识
- type 区分系统管理员和企业管理员
- eid 用户所属企业id
- username 用户名
- mobile 绑定手机号
- passwd 密码
- status 状态
- 角色表 role
- id 角色标识
- eid 角色所属企业id
- status 角色状态,启用&禁用
- name 角色名称
- 权限表 rule
- id 权限标识
- parent_id 父级标识
- name 权限名称
- title 权限描述
- 行为表 action
- id 操作标识
- name 操作api地址
- 用户与角色关联表 user_role
- id
- user_id 用户id
- role_id 角色id
- 角色权限关联表 role_rule
- id
- role_id 角色id
- rule_id 权限id
- 权限行为关联表 rule_action
- id
- rule_id 权限id
- action_id 行为id
实现逻辑
企业管理员的权限树
企业管理员可以分配除权限管理以外的其他业务权限,根据业务具体细分浏览、编辑、删除等子权限
- 业务权限A - 业务权限A 浏览 - 业务权限A 编辑 - 业务权限A 删除 - 业务权限B - 业务权限B 浏览 - 业务权限B 编辑 - 业务权限B 删除 - ...
权限树可以用递归方式处理:
function getAuthorityByParentId($menus, $pid = AuthRule::TOP_LEVEL){ $tree = array(); foreach ($menus as $menu){ if($menu['parent_id'] == $pid){ $menu = $menu->visible($this->authRuleVisible)->toArray(); $child = $this->getAuthorityByParentId($menus, $menu['id']); $menu['children'] = $child; $tree[] = $menu; } } return $tree; }
企业管理员对角色的管理:新建、修改、删除
对角色的编辑关联对应权限,一个角色对应多个权限。
企业管理员对账户的管理:新建、修改、删除
对账户的编辑关联对应角色,一个账户可以对应多个角色,关联角色的权限合并。
子企业根据权限获取菜单栏树
获取菜单栏树方法可复用权限树方法。
进入界面访问的每个接口,根据登录用户获取相对应角色所对应的权限判断是否有访问该接口的权限。
在新建角色的时候建立 Role - Action 对应缓存,在修改角色的时候更新缓存。用户访问接口,根据用户启用的角色判断是否有访问接口权限。判断方法在控制器构造函数中注入。