3+1 张表建立一个强大的RBAC鉴权管理系统

讲在前面的

我们一般在开发后台管理应用程序的时候,或多或少都会涉及到鉴权管理。鉴权管理中一般有角色、权限两部分组成,用户直接和角色关联,这种鉴权管理实现简单,在一些较小的项目中也比较容易实现,但是在一些比较大的项目中就有些局限性了,或者说对权限的要求更高、更细粒度。下面我主要讲下如果通过3+1来实现鉴权管理。


3 指的是3张鉴权表设计

  • yauth_items,这张表记录的是鉴权节点表,表结构如下:
CREATE TABLE `yauth_items` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `item_code` VARCHAR(191) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `client_id` INT(10) UNSIGNED NULL DEFAULT NULL,
    `user_id` INT(10) UNSIGNED NULL DEFAULT NULL,
    `item_name` VARCHAR(191) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `item_desc` VARCHAR(191) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `item_type` TINYINT(3) UNSIGNED NOT NULL,
    `scope` VARCHAR(191) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `other_data` TEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `deleted_at` TIMESTAMP NULL DEFAULT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `yauth_items_item_code_unique` (`item_code`)
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB;
  • yauth_item_relation,这张表记录的是鉴权节点之间的层级关系
CREATE TABLE `yauth_item_relation` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `item_id` INT(10) UNSIGNED NOT NULL,
    `client_id` INT(10) UNSIGNED NOT NULL,
    `scope` VARCHAR(191) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `parent_id` INT(11) NULL DEFAULT NULL,
    `lft` INT(11) NULL DEFAULT NULL,
    `rgt` INT(11) NULL DEFAULT NULL,
    `depth` INT(11) NULL DEFAULT NULL,
    `deleted_at` TIMESTAMP NULL DEFAULT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    INDEX `yauth_menus_item_id_index` (`item_id`),
    INDEX `yauth_menus_parent_id_index` (`parent_id`),
    INDEX `yauth_menus_lft_index` (`lft`),
    INDEX `yauth_menus_rgt_index` (`rgt`)
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB;
  • yauth_item_group,这张表是记录鉴权节点之间的依赖关系
CREATE TABLE `yauth_item_group` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `parent_id` INT(10) UNSIGNED NOT NULL,
    `child_id` INT(10) UNSIGNED NOT NULL,
    `client_id` INT(10) UNSIGNED NOT NULL,
    `scope` VARCHAR(191) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `deleted_at` TIMESTAMP NULL DEFAULT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    INDEX `yauth_item_relation_parent_id_index` (`parent_id`),
    INDEX `yauth_item_relation_child_id_index` (`child_id`)
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB;

1 指的是用户分配(关联)表设计

  • yauth_assignments,这张表指的是用户和鉴权节点如何进行分配(关联)
CREATE TABLE `yauth_assignments` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `item_id` INT(10) UNSIGNED NOT NULL,
    `user_id` INT(10) UNSIGNED NOT NULL,
    `provider` VARCHAR(191) NOT NULL COLLATE 'utf8mb4_unicode_ci',
    `deleted_at` TIMESTAMP NULL DEFAULT NULL,
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    INDEX `yauth_assignments_user_id_index` (`user_id`),
    INDEX `yauth_assignments_item_id_index` (`item_id`)
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB;

简单说下鉴权管理的思路

  • 一切皆节点,节点包括权限、菜单、角色等等
  • 节点之间没有显示的层级关系,比如菜单包含权限,角色包含权限,但是权限不能包含菜单,这个需要根据需求在代码里面实现
  • 权限、菜单、角色三者之间的关系如下,并且同级之间也可以相互包含,比如角色A包含角色B,当然,你可以根据自己的需求代码里面去控制


    权限、菜单、角色关系
  • 我把4张表的一个ER图大概画了一下,标注了里面节点的一些含义


    表之间的关联关系

下面解读下表结构

yauth_items表 = 权限条目表

  • item_code = 节点代码 // 用来做唯一标识
  • client_id = 客户端ID // 用来标识是哪个客户端访问过来的用户,你总不想每做一个客户端都写一套rbac系统吧,比如有clientAclientB,业务功能不同,权限也不同,通过client_id我们就能根据client找到该机构下拥有的权限,来判断权限该用户是否有权限
  • user_id = 用户ID
  • item_name = 节点名称 // 比如该节点是一个菜单、它的名字叫 首页
  • item_desc = 节点描述 // 给节点添加更详细的描述信息
  • item_type = 节点类型 // 节点的类型 权限、菜单、角色,可以根据需要扩充
  • scope = 作用域 // 将这些节点进行作用域划分,比如同样是菜单,分为顶部菜单和左侧菜单,多个作用域用逗号隔开,比如超管的菜单和机构的菜单
  • other_data = 其他数据// 扩展字段,我们可以为某些节点添加一些别的标识以便做特殊处理

yauth_item_relation表 = 节点关系表

  • item_id = 节点id // 对应yauth_items表id
  • client_id = 客户端ID // 同上,标识归属于哪个客户端
  • scope = 作用域 // 该节点属于哪个作用域,单一作用域
  • parent_id = 父id // 关联本表的id字段
  • lft = 左值 // 详情可见左右值算法
  • right = 右值 // 详情可见左右值算法
  • depth = 层级 // 代表该节点的层级深度

yauth_item_group表 = 节点分组表

  • parent_id = 父ID // 关联yauth_items表的id字段
  • child_id = 子ID // 关联yauth_items表的id字段
  • client_id = 客户端ID // 区分客户端
  • scope = 作用域 // 建立依赖时,在哪个作用域范围添加的

yauth_assignments = 权限分配表

  • item_id = 节点ID // yauth_items表id
  • user_id = 用户ID //
  • provider = 用户提供这 // 用来标识是哪个表提供的用户,适用于多表用户

总结:

  • yauth_items 用来存储节点,我们添加的所有节点都在这样表中
  • yauth_item_relation 用来表示节点的层级关系,不然我们看到视图不够直观。注意,添加到yauth_items表是第一步,我们将节点挂载到yauth_item_relation表,才应该生效
  • yauth_item_group 用来标识节点之间的依赖关系,角色A依赖角色B,角色B依赖菜单A、菜单B,菜单A依赖权限A,给用户分配了角色A相当于拥有了角色B、带单A、菜单B、权限A
  • 这套设计操作起来可能会比较麻烦,比如添加权限这个操作,需要先添加、在挂载、在添加依赖,不过权限这个东西本来不就随着业务要求越高越复杂么
  • 在依赖判断时,yauth_item_group表parent_id 和 child_id 递归查找依赖关系,可能会导致大量递归,使用左右值又丧失了依赖的优点,暂时没有想到好的解决办法
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容