动态菜单/RBAC标准完整权限管理系统的实现,通用角色权限控制系统五张表逻辑关联设计实现
序言:
众所周知,RBAC(Role-Based Access Control,基于角色的访问控制)权限系统是每个系统里面必备的最基本的系统,然而权限系统设计有时挺麻烦的,现在整理了下,给正在开发此模块的朋友一个思路!
设计基础:用户、角色、权限三大核心表,加上用户角色、角色权限两个映射表(用于给用户表关联上权限表)。这样就可以通过登录的用户来获取权限列表,或判断是否拥有某个权限。
大致用到5张表:用户表(s_user)、角色表(s_role)、菜单表(s_menu)、用户角色表(s_user_role)、角色菜单表(s_role_menu)<注:表前加前缀s代表这些是系统表,表名划分业务范畴,mysql中命名尽量全部采用小写,mysql在windows下是不区分大小写的,但是在linux下严格区分的,而且java或者mybatis这些持久层操作都是严格区分大小写的,为了不至于混乱。建议全小写或全大写,如果是sql server则建议驼峰命名方式比如:s_UserRole(我个人也比较喜欢这种)>。
各表的大体表结构如下:
- 1、用户表(s_user):user_id,user_name、pwd,state,user_type
- 2、角色表(s_role):role_id,role_name,description
- 3、菜单表(s_menu):menu_id,menu_pid,sort,menu_name,func_name,is_enabled,description
- 4、用户角色表(s_user_role):urid、user_id、role_id
- 5、角色菜单表(s_role_menu):rmid、role_id、menu_id
任何权限的需求,都是为广义的用户分配角色,角色拥有广义的权限。角色是最重要的中枢,隐藏做幕后黑手,从不出现在业务代码里,用行话说就是解除了用户和权限的直接耦合。
角色把用户群体抽象化,几百个用户变成几个特殊定义的角色,用户->角色->权限写成通用判断权限的方法:currUser.IsHave(xx权限)。核心就是一个sql联表查询语句,查询条件为用户id。
例如:
部门权限:部门也是一种角色,建立 部门表、部门角色表。通用权限方法里加上 当前部门->部门所属角色->权限
职位权限:职位也是一种角色,建立职位表、职位角色表,同上
细分下来,菜单其实就是一种功能模块对象,建立 菜单表、角色菜单表,就把菜单纳入了权限管理范畴。通用权限方法里加上 角色列表->权限、菜单即实现了菜单权限界定,动态菜单功能
上述权限模型使用mysql 通用建表语句如下:
-- 1、用户表(s_user):user_id,user_name、pwd,state,user_type create table s_user ( user_id varchar(50) not null, -- 用户ID user_name varchar(100), -- 用户名 pwd varchar(50), -- 密码(md5加密) state int, -- 用户状态(0:启用,1禁用) user_type varchar(50), -- 用户类型(用于用户分组,比如管理员,省级,市级,县级,etc.) CONSTRAINT pk_s_user_user_id PRIMARY KEY(user_id) -- 主键 ); -- 2、角色表(s_role):role_id,role_name,description create table s_role ( role_id varchar(50) not null, -- 角色ID role_name varchar(100), -- 角色名 description varchar(1000), -- 角色描述 CONSTRAINT pk_s_role_role_id PRIMARY KEY(role_id) -- 主键 ); -- 3、菜单表(s_menu):menu_id,menu_pid,sort,menu_name,func_name,is_enabled,description create table s_menu ( menu_id varchar(50) not null, -- 菜单ID menu_name varchar(100), -- 菜单名 menu_pid varchar(50) not null, -- 菜单父ID (这样可以做到无限级子菜单) sort int, -- 菜单排序(int型,控制菜单显示顺序) func_name varchar(100), -- 该菜单执行方法函数(可以是url接口地址或者FunctionName) is_enabled int, -- 是否启用该菜单(int型,控制菜单显示与否,0:启用,1:禁用) description varchar(1000), -- 菜单功能描述 CONSTRAINT pk_s_menu_menu_id PRIMARY KEY(menu_id) -- 主键 ); -- 4、用户角色表(s_user_role):urid、user_id、role_id create table s_user_role ( urid varchar(50) not null, -- 用户角色ID user_id varchar(50), -- 用户ID role_id varchar(50), -- 角色ID CONSTRAINT pk_s_user_role_urid PRIMARY KEY(urid) -- 主键 ); -- 5、角色菜单表(s_role_menu):rmid、role_id、menu_id create table s_role_menu ( rmid varchar(50) not null, -- 角色菜单ID role_id varchar(50), -- 角色ID menu_id varchar(50), -- 菜单ID CONSTRAINT pk_s_role_menu_rmid PRIMARY KEY(rmid) -- 主键 );
说明:上面凡是用到主键级别的id的,一律建议采用uuid,s_user表的user_id建议为了实现唯一性,可采用类似身份证学员证一类的规则编号实现唯一性,不建议采用用户名拼音首字母,如果用户id是在注册时自动生成则好控制。可实时检测是否重名。
在如上图的权限5表设计模式下,某个用户登录,我们要如何查找该用户的菜单权限呢?流程如下 :
登录验证查询顺序
- 1,根据登录用户名密码查询用户表(s_user)验证登录,关联表(s_user,s_department) 如果有部门表的话。
- 2,登录验证通过,根据用户id,查询用户角色表(s_user_role)获取该用户拥有的所有角色id。
- 3,根据步骤2获得的所有角色id,查询角色表(s_role),获取所有角色名称(这个步骤可选,如果需要展示用户角色的话)。
- 4,根据获得的该用户角色id,查询角色菜单表(s_role_menu),获取该用户的所有菜单id
- 5,根据步骤4获得的菜单id,查询菜单表(s_menu)获得该用户id所拥有的所有菜单信息,从而得到完整用户菜单列表。
- 6,返回数据到前台展示
大家可以自行添加测试数据进行测试,然后编写相应的表数据操作模块,完成整个权限系统的开发
添加权限控制数据5张表CRUD模块,大约需要完成如下内容:
- 1,用户管理页面,实现对用户的crud操作,操作表[s_user]
- 2,角色管理页面,实现对角色的crud操作,操作表[s_role]
- 3,菜单管理页面,实现对菜单的crud操作,操作表[s_menu]
- 4,在角色管理页面,同时需实现用户角色定义,操作表[s_user_role]
- 5,在角色管理页面还要同时实现角色菜单定义,操作表[s_role_menu]
相信看到这里,整个权限系统已经呼之欲出,大家已经很清楚自己该怎么做了,开动起来吧。一个完美的权限系统就诞生在你的手中了。
作者原创文章,写作不易,转载请注明出处,谢谢,觉得看完有益也欢迎用你发财的小手点赞收藏关注!
本文来自博客园,作者:IT情深,转载请注明原文链接:https://www.cnblogs.com/wh445306/p/16751759.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?