RBAC 模型的简单实现

RBAC 模型基本介绍

RBAC(Role-Based Access Control,基于角色的访问控制)是一种广泛应用的权限管理模型。它的核心思想是通过角色来管理权限,而不是直接分配权限给用户。用户被赋予一个或多个角色,而每个角色拥有不同的权限。

RBAC 的核心组件

用户(User):系统的使用者。
角色(Role):一组权限的集合。
权限(Permission):对系统资源的具体操作(如读、写、删除等)。
用户-角色分配(User-Role Assignment):将用户与角色关联。
角色-权限分配(Role-Permission Assignment):将角色与权限关联。

RBAC 的工作流程

  1. 管理员定义角色(如管理员、编辑、访客)。
  2. 为每个角色分配相应的权限(如管理员可以读写,访客只能读)。
  3. 将用户分配到相应的角色。
  4. 用户通过角色间接获得权限

举例:

场景:
存在某系统,系统包含 1 ~ 10 个菜单目录,现在用户群体 A 需要拥有 1~3 的菜单权限,用户群体 B 需要拥有 3~5 菜单的权限,用户群体 C 需要拥有 6~10 的菜单权限…


RBAC 处理方式:

  1. 系统管理员定义角色,为用户群体 A 创建角色 A1,A1包含 1~3 的菜单权限,为用户群里 B 创建角色 A2…
  2. 将角色分配到不同用户群体。
  3. 不同用户根据分配到的角色,间接获得系统的部分权限。

RBAC 优缺点

优点

  1. 简化权限管理:通过角色间接分配权限,减少了直接管理用户权限的复杂性。
  2. 易于扩展:新增用户只需分配角色,无需重新定义权限。
  3. 支持最小权限原则:可以为角色分配最小必要的权限,降低安全风险。
  4. 适合多用户系统:在企业级应用中,RBAC 可以很好地支持复杂的权限需求。

缺点

  1. 角色爆炸问题:当角色过多时,管理角色本身会变得复杂。
  2. 灵活性不足:对于需要动态权限的场景(如基于时间、地点的权限),RBAC 的支持较弱。
  3. 权限粒度有限:RBAC 的权限控制通常是粗粒度的,难以实现细粒度的权限控制。

RBAC 的实现

数据库设计

图中由左至右,依次为:菜单表、菜单-角色对应表、角色表、角色-用户对应表、用户表;
菜单表和角色表之间为多对多关系;
角色表和用户表之间为多对多关系;
在这里插入图片描述

后端实现(SpringBoot + SaToken)

    @PostMapping("/addMenu")  @Operation(summary = "新增菜单")@SaCheckPermission("system:menu:add")   // 只有用户含有该权限标识符,才会放行请求,否则抛出异常public ResponseResult addMenu(@Validated @RequestBody MenuForm menuForm) {log.info("addMenu:{}", menuForm);menuService.addMenu(menuForm, StpUtil.getLoginId().toString());return ResponseResult.ok().message("添加成功");}

SaCheckPermission实现原理

/** SaToken 处理逻辑 **/public void checkPermissionAnd(String... permissionArray){// 先获取当前是哪个账号idObject loginId = getLoginId();// 如果没有指定权限,那么直接跳过if(permissionArray == null || permissionArray.length == 0) {return;}// 获取该用户的所有权限List<String> permissionList = getPermissionList(loginId);for (String permission : permissionArray) {// 判断该权限是否在该用户的权限列表中,若不存在,则抛出 NotPermissionException 异常if(!hasElement(permissionList, permission)) {throw new NotPermissionException(permission, this.loginType).setCode(SaErrorCode.CODE_11051);}}}

前端实现

/** 前端动态路由 **/
const dynamicRoutesFromBackend = (backendRoutes: MenuEntity[]): RouteType[] => {// 辅助函数:如果路径以 '/' 开头,则去掉 '/'const normalizePath = (path?: string): string => {return path && path.startsWith('/') ? path.slice(1) : path || ''; // 确保路径存在后再处理};// 生成动态路由const dynamicChildren: RouteType[] = [];backendRoutes.filter(route => route.status === 1).forEach(route => {if (route.menuType === 'M') {const normalizedPath = normalizePath(route.path);if (normalizedPath && !route.children) {dynamicChildren.push({path: normalizedPath,element: withLoadingComponent(lazy(() =>(modules[`/src/views/${normalizedPath}/index.tsx`]?.().then((module) => ({ default: (module as { default: React.ComponentType }).default })))  // 类型断言|| import('../views/Error').then((module) => ({ default: (module as { default: React.ComponentType }).default })))),children: []});}if (!route.path && route.children) {route.children.forEach(childRoute => {const normalizedChildPath = normalizePath(childRoute.path);dynamicChildren.push({path: normalizedChildPath,element: withLoadingComponent(lazy(() =>modules[`/src/views/${normalizedChildPath}/index.tsx`]? (modules[`/src/views/${normalizedChildPath}/index.tsx`] as () => Promise<{ default: React.ComponentType }> )()  // 使用类型断言并确保返回 Promise<{ default: React.ComponentType }>: import('../views/Error').then((mod) => ({ default: mod.default }))  // 错误页面的处理)),children: []});});}}});
/**动态加载菜单**/
function covertRoutesToMenuItems(routes: RouteType[]): MenuItem[] {// 查找 path 为 '/' 的根路由const rootRoute = routes.find(route => route.path === '/');if (!rootRoute || !rootRoute.children) {return [];}// 递归解析子路由const convertToMenu = (routeList: RouteType[]): MenuItem[] => {return routeList.filter(route => !route.hidden) // 过滤掉 hidden 为 true 的路由.map(route => ({key: route.path,label: route.name,icon: route.icon,children: route.children ? convertToMenu(route.children) : undefined,  // 递归处理子菜单}));};// 开始处理 '/' 的子路由return convertToMenu(rootRoute.children);
}

完整代码

前端完整代码地址 : Gitee
后端完整代码地址 : Gitee

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/72325.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/72325.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构---堆栈和列

一、堆栈 1.栈堆&#xff1a;具有一定操作约束的线性表&#xff1b;&#xff08;只在一端做插入删除&#xff09; 2.栈的顺序存储结构&#xff1a; 由一个一维数组和一个记录栈顶元素位置的变量组成。定义方式如下&#xff1a; 3.入栈操作&#xff1a; 注意&#xff1a;&…

2023 年全国职业院校技能大赛(中职组)移动应用与开发赛项 赛题第十套

2023 年全国职业院校技能大赛&#xff08;中职组&#xff09;移动应用与开发赛项 赛题第十套&#xff09; 移动应用与开发赛项竞赛模块 A&#xff1a;移动应用界面设计任务 1 环保中心界面设计&#xff08;7.5 分&#xff09;任务 2&#xff1a;首页界面设计&#xff08;7.5 分…

FPGA为何要尽量减少组合逻辑的使用

在FPGA设计中&#xff0c;组合逻辑的使用确实需要谨慎&#xff0c;尤其是要尽量减少它的复杂性。这并不是因为组合逻辑本身不好&#xff0c;而是因为它在实际应用中容易引发一系列问题&#xff0c;而这些问题往往与FPGA的设计哲学和硬件特性相冲突。让我从几个关键点来和你聊聊…

c语言笔记 字符串函数---strcmp,strncmp,strchr,strrchr

目录 函数strcmp与strncmp 以下是错误的示范&#xff1a;两个指针字符型的指针不能直接进行比较 函数strchr与函数strrchr 函数strchr与函数strrchr与strstr函数三者对比 背景&#xff1a;如果说我们要比较两个字符串是否相等&#xff0c;使用strcmp或者strncmp函数。在c语言中…

合React宝宝体质的自定义节流hook

本文为开发开源项目的真实开发经历&#xff0c;感兴趣的可以来给我的项目点个star&#xff0c;谢谢啦~ 具体博文介绍&#xff1a; 开源&#xff5c;Documind协同文档&#xff08;接入deepseek-r1、支持实时聊天&#xff09;Documind &#x1f680; 一个支持实时聊天和接入 - 掘…

【RTSP】客户端(五)H264 265处理逻辑

H264处理逻辑 整体逻辑分析 实现逻辑 解析 RTP 包头&#xff1a;首先检查 RTP 头部的有效负载类型&#xff08;payloadType&#xff09;是否匹配处理扩展头&#xff1a;如果 RTP 包包含扩展头&#xff0c;跳过扩展头部分&#xff0c;获取有效负载处理分片数据&#xff1a;H264…

IDEA集成git,项目的克隆,远程仓库中文件的添加删除

目录 一、克隆项目 二、使用IDEA完成文件的上传和删除 1.配置git 2.上传 3.删除&#xff08;通过git bash&#xff09; 一、克隆项目 点击克隆&#xff0c;复制url &#xff0c;如下 打开你想要克隆到哪里&#xff0c;右击&#xff0c;选择 open Git Bash here 这一步之后…

神经网络:定义与核心原理

神经网络&#xff08;Artificial Neural Network, ANN&#xff09;是一种受生物神经系统启发的计算模型&#xff0c;旨在通过模拟神经元之间的连接与信息传递机制&#xff0c;实现复杂的数据处理和模式识别功能。其本质是由大量简单处理单元&#xff08;神经元&#xff09;构成…

将pdf或者word转换成base64格式

废话不多说直接上代码&#xff1a; function fileToBase64(file) {return new Promise((resolve, reject) > {const reader new FileReader();reader.readAsDataURL(file);reader.onload function (event) {const base64Data event.target.result.split(,)[1];resolve(b…

Spring @Bean注解使用场景二

bean:最近在写一篇让Successfactors顾问都能搞明白的sso的逻辑的文章&#xff0c;所以一致在研究IAS的saml2.0的协议&#xff0c;希望用代码去解释SP、idp的一些概念&#xff0c;让顾问了解SSO与saml的关系&#xff0c;在github找代码的时候发现一些代码的调用关系很难理解&…

ubuntu22.04 关于挂在设备为nfts文件格式无法创建软连接的问题

最近遇到情况&#xff0c;解压工程报错&#xff0c;无法创建软连接 但是盘内还有130G空间&#xff0c;明显不是空间问题&#xff0c;查找之后发现是移动硬盘的文件格式是NTFS&#xff0c;在ubuntu上不好兼容&#xff0c;于是报错。 开贴记录解决方案。 1.确定文件格式 使用命…

docker后台运行,便于后期用命令行进入它的终端

在 docker compose up --build -d 命令中&#xff0c;​**-d​&#xff08;或 --detach&#xff09;参数的作用是让容器以后台模式&#xff08;detached mode&#xff09;​**运行。以下是详细解释&#xff1a; ​**-d 参数的作用** ​后台运行容器&#xff1a; 默认情况下&a…

网页制作14-Javascipt时间特效の显示动态日期

<!doctype html> <html> <head> <meta charset"utf-8"> <title>动态日期</title> </head><script>var today new Date();//获取时间var ytoday.getFullYear();//截取年var mtoday.getMonth();//截取月份,返回0~11v…

【BP神经网络】实战

1.参考Python实战&#xff1a;BP神经网络_bp神经网络实战python-CSDN博客 2.实践 &#xff08;1&#xff09;运行环境 anocanda Powershell Prompt&#xff08;anocanda3&#xff09; &#xff08;2&#xff09;创建虚拟环境&#xff0c;解决安装包的版本问题 *打开终端&a…

深度学习多模态人脸情绪识别:从理论到实践

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。https://www.captainbed.cn/north 文章目录 1. 引言2. 技术框架与流程图3. 核心算法解析3.1 视觉特征提取&#xff08;CNN&#xff09;3.2…

ssh通过22端口无法连接服务器问题处理

一&#xff0c;安全组开放22端口 root无法连接服务器&#xff0c;22端口也开放了&#xff0c;可能是防火墙开启了拦截。 二&#xff0c;检测防火墙状态 查看防火墙状态 sudo firewall-cmd --state 关闭防火墙 sudo systemctl stop firewalld 开启防火墙 sudo systemctl sta…

element 的tab怎么动态根据参数值添加一个vue页面

在使用 Element UI 的 Tabs 组件时&#xff0c;动态添加 Vue 组件或页面可以通过操作 tabs 数组来实现。假设你要根据参数值来动态添加一个 Vue 页面&#xff08;这里假设是一个 Vue 组件&#xff09;&#xff0c;你可以按照以下步骤操作&#xff1a; 首先&#xff0c;确保你已…

Docker封装镜像、分发、部署实践:nginx

在实际生产工作中&#xff0c;通常是没法直接访问公网的&#xff0c;但是有经常需要使用Docker部署应用&#xff0c;本文将介绍使用Docker从拉取nginx、打包、分发到加载部署nginx的全流程&#xff01; 1 准备工作 1.1 安装docker 请参考&#xff1a;Docker入门指南&#xff…

LuaJIT 学习(5)—— string.buffer 库

文章目录 Using the String Buffer LibraryBuffer ObjectsBuffer Method Overview Buffer Creation and Managementlocal buf buffer.new([size [,options]]) local buf buffer.new([options])buf buf:reset()buf buf:free() Buffer Writersbuf buf:put([str|num|obj] [,……