一般web系统操作人员多时都会需求权限管理,一来限制操作范围,二来限制数据公开度。

现在最流行的一个模式为 RBAC (Role-Based Access Control) 基于角色的访问控制。设定权限范围定义到角色中,然后再分配到每个用户。

这里仅以一般后台管理系统为例,叙说数据结构:

需求:

  1. 菜单需要针对不同部门使用不同的菜单结构。

  2. 权限项能精确到页面中某个内容或局部功能。

基本要求:没有权限的菜单,页面中内容或链接禁止显示。

表结构

CREATE TABLE `power_item` (  `power_item_id` int UNSIGNED primary key auto_increment,  `name` varchar(35) not null comment '权限项名称',  `code` varchar(80) unique not null comment '权限项代码',  `power_item_group_id` int unsigned not null comment '权限项组ID',  `status` enum('disable','enable') NOT NULL DEFAULT 'enable' COMMENT '启用或禁用,enable为启用',  `comment` varchar(1000) not null default '' comment '备注说明',  `created_at` int unsigned not null comment '创建时间',  `updated_at` int unsigned not null comment '修改时间') ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='权限项表';CREATE TABLE `power_item_group` (  `power_item_group_id` int UNSIGNED primary key auto_increment,  `name` varchar(35) not null comment '权限项组名称',  `comment` varchar(1000) not null default '' comment '备注说明',  `created_at` int unsigned not null comment '创建时间',  `updated_at` int unsigned not null comment '修改时间') ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='权限项组表';CREATE TABLE `power_role` (  `power_role_id` int UNSIGNED primary key auto_increment,  `name` varchar(35) not null comment '角色名',  `status` enum('enable','disable') not null default 'enable' comment '启用或禁用,enable为启用',  `comment` varchar(1000) not null default '' comment '备注说明',  `created_at` int unsigned not null comment '创建时间',  `updated_at` int unsigned not null comment '修改时间') ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='角色表';CREATE TABLE `power_role_item` (  `id` int UNSIGNED primary key auto_increment,  `power_role_id` int unsigned not null comment '角色ID',  `power_item_id` int unsigned not null comment '权限项ID',   unique key role_item(power_role_id,power_item_id)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='角色与权限项关联表';CREATE TABLE `power_role_admin` (  `id` int UNSIGNED primary key auto_increment,  `power_role_id` int unsigned not null comment '角色ID',  `admin_id` int unsigned not null comment '管理员ID',   unique key role_admin(power_role_id,admin_id)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='角色与管理员关联表';CREATE TABLE `power_menu_group` (  `power_menu_group_id` int UNSIGNED primary key auto_increment,  `name` varchar(35) not null comment '菜单组名',  `comment` varchar(1000) not null default '' comment '备注说明',  `created_at` int unsigned not null comment '创建时间',  `updated_at` int unsigned not null comment '修改时间') ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='菜单组表';CREATE TABLE `power_menu` (  `power_menu_id` int UNSIGNED primary key auto_increment,  `name` varchar(35) not null comment '菜单名',  `url` varchar(60) not null comment '链接地址',  `power_item_id` int unsigned not null default 0 comment '关联权限项ID',  `comment` varchar(1000) not null default '' comment '备注说明',  `created_at` int unsigned not null comment '创建时间',  `updated_at` int unsigned not null comment '修改时间') ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='菜单表';CREATE TABLE `power_menu_level` (  `id` int UNSIGNED primary key auto_increment,  `power_menu_id` int unsigned not null default 0 comment '菜单ID',  `power_menu_group_id` int unsigned not null default 0 comment '所属菜单组ID',  `parent_id` int unsigned not null default 0 comment '上级层级ID',  `sort` smallint unsigned not null default 0 comment '排序值,大到小',  unique key menu_level(power_menu_id,power_menu_group_id,parent_id)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='菜单层级关联表';

关联关系图

对应关系

  1. 角色与权限项通过 power_role_item 表随意组合

  2. 角色与管理员通过 power_role_admin 表随意组合

  3. 菜单与菜单组通过 power_menu_level 表随意组合(包含菜单层级关系)

设计思想

角色只是划分范围或添加维度方便理解,实际使用中很多管理员扮演了多种角色,所以一个管理员允许同时拥有N个角色。

权限项相当于一把锁,程序在关键地方安装对应的锁,然后把这些锁的钥匙分配给不同的角色,所以权限项与角色之间是多对多关系,即一个权限项可以关联多个角色,而一个角色也可以关联多个权限项。

权限项组只是为了把众多的权限项进行简单的分组,以便角色在勾选权限项时能把权限项分组展示,比如,权限管理相关,会员管理相关,订单管理相关等,这样在勾选时会更容易操作。

菜单可以关联到对应的权限项,这样可以过滤掉没有权限的菜单显示,为了方便不同部门菜单结构不同的目的,额外添加了菜单层级与菜单组,这样一来,每个管理员只显示自己所在的菜单组的菜单结构,中间相对复杂点的就是菜单结构组合处理,power_menu_level 表中需要保存当前菜单,上级菜单,及菜单组,和排序。

备注说明

角色设计中弃用所谓的上级角色关系(即角色继承)感觉很高尚的设计,实际容易造成误解,误操作,程序复杂化等问题,比如继承会拥有上级权限那么对实际分配人员对角色的理解就不仅限于当前角色还得考虑上级角色否则容易造成权限分配过度,再者继承的权限在权限查询中存在着递归结构,复杂化判断程序,如果不继承权限那这个功能形同虚设,当然如果只是为了给角色分类,完全可以增加一个角色组表,进行区分。

菜单弃用了单一预定义好的结构,使用了可自定义的菜单结构,也只是为了满足不同部门菜单结构的需求,当前这块功能并非必需的,在实际应用中是可选的。

以上内容为个人观点或想法,如有不妥还请纠正。

欢迎安装

composer require xihuan/laravel-crbac