Django Web开发:构建强大RBAC权限管理系统的实战指南

在这里插入图片描述


文章目录

  • 前言
  • 一、rbac 基于角色的权限管理
    • 1.acl 基于用户的权限管理
    • 2.rbac 基于角色的权限管理
  • 二、应用示例
    • 1.配置角色资源
      • a.分析表
      • b.核心逻辑
      • c.使用transfer在前端实现资源配置
      • d.页面效果
    • 2.登录时获取对应权限
      • a.员工登录
      • b.中间件
      • c.前端请求
      • d.效果图
    • 3.前端-路由守卫-页面权限
  • 三、拓展


前言

    随着软件系统的日益复杂,权限管理成为确保系统安全与数据隐私的关键。传统ACL模型虽基础但受限,而RBAC模型以其灵活性和高效性逐渐成为主流。本文将简要回顾ACL概念,并深入解析RBAC的核心机制,包括角色定义、权限分配及用户角色关联。同时,将详细阐述RBAC在实际项目中的操作实践,如配置角色资源、动态获取用户权限及前端页面权限控制等。


一、rbac 基于角色的权限管理

1.acl 基于用户的权限管理

ACL(Access Control List,访问控制列表) 基于用户的权限管理

用户表:id、name、mobile、password1 张三	18612340000	1232 李四	18631240001	1329
资源表:id、name、pid1 内容菜单 null2 用户菜单 null3 课程管理  14 课程分类  15 用户管理  2
用户资源表:userid、resid1		31		42		5

2.rbac 基于角色的权限管理

rbac基于角色的权限管理

用户表:id、name、mobile、password、roleid1 张三	18612340000	1232 李四	18631240001	1329
角色表:id、name1 编辑人员	2 推广员3 财务专员
资源表:id、name、pid、url1 内容菜单 null2 用户菜单 null3 课程管理  1  /course/4 课程分类  1  /cates/5 用户管理  2  /user/
角色资源表:userid、resid1		31		42		5

流程:
员工入职–>管理员—>添加角色、添加资源、角色配置资源、添加用户(选择角色)—>用户登录—>手机号验证码—>验证通过,通过后查询此用户对应的资源(页面资源、接口资源)—>把页面资源返回给前端—>把接口资源存入redis—>在中间件验证是否有接口权限

二、应用示例

1.配置角色资源

a.分析表

user/models.py:资源表、角色表、用户表、角色资源表、接口权限表

from django.db import models# Create your models here.
# 资源表
class ResourceModel(models.Model):name = models.CharField(max_length=10, unique=True, default="默认模块")pid = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='son')url = models.CharField(max_length=20, unique=True)def __str__(self):return self.nameclass Meta:verbose_name = "资源表"verbose_name_plural = "资源表"db_table = 'resource'# 角色表
class RoleModel(models.Model):name = models.CharField(max_length=10,unique=True ,default="角色")resource = models.ManyToManyField(ResourceModel)def __str__(self):return self.nameclass Meta:verbose_name = "角色表"verbose_name_plural = "角色表"db_table = 'role'# 用户表
class UserModel(models.Model):username = models.CharField(max_length=10, default='默认用户名')phone = models.CharField(max_length=11, unique=True)password = models.CharField(max_length=10, default='123')role = models.ForeignKey(RoleModel, on_delete=models.CASCADE,default=2)def __str__(self):return self.usernameclass Meta:verbose_name = "用户表"verbose_name_plural = "用户表"db_table = 'user'# 接口权限表:
class InterfacePerModel(models.Model):resource = models.ManyToManyField(ResourceModel,related_name="interfaces")url = models.CharField(max_length=20, unique=True)def __str__(self):return self.urlclass Meta:verbose_name = '接口权限表'verbose_name_plural = '接口权限表'db_table = 'interface_per'

b.核心逻辑

# 获取角色对应信息
class RoleView(APIView):def get(self, request):data = RoleModel.objects.all()roleSer = RoleSerializer(data, many=True)return Response({"message":"获取角色资源对应信息","code":200,"data":roleSer.data})class ResourceView(APIView):def get(self, request):# 拿 roleid# 拿 roleid 对应的资源,roleid = request.GET.get('roleid')res = ResourceModel.objects.filter(pid_id__gt=0).all()# transf -- key -- labelallres = [{"key":i.id,"label":i.name} for i in res] #pid>0,所有资源role = RoleModel.objects.filter(id=roleid).first()checkres = role.resource.all() #拿这个角色对应的所有资源(选中)checkedids = [i.id for i in checkres] #拿对应的所有资源id(选中)return Response({"code":200,"allres":allres,"checkedids":checkedids})def post(self, request):resids = request.data.get("resids")roleid = request.data.get("roleid")role = RoleModel.objects.filter(id=roleid).first()print(role.resource.all())if role.resource.all():role.resource.clear()#清除之前存在的所有资源role.resource.add(*resids)#添加传进来的 资源 idsreturn Response({"code":200})

c.使用transfer在前端实现资源配置

使用 el-transfer 构建角色资源配置页面

<template><el-table :data="tableData" style="width: 100%"><el-table-column prop="name" label="角色名" width="120" /><el-table-column fixed="right" label="Operations" width="120"><template #default="scope"><el-button link type="primary" size="small" @click="handleClick">Detail</el-button><el-button link type="primary" size="small">Edit</el-button><el-button link type="primary" size="small" @click="setres(scope.row.id)">资源配制</el-button></template></el-table-column></el-table><el-dialog v-model="dialogVisible" title="Tips" width="80%"><el-transfer v-model="value" :data="data" /><template #footer><span class="dialog-footer"><el-button @click="dialogVisible = false">Cancel</el-button><el-button type="primary" @click="addresource">Confirm</el-button></span></template></el-dialog></template><script setup>
import http from "../../http";
import {onMounted,ref} from 'vue'const dialogVisible=ref(false)
const value=ref([])
const data = ref([])
const roleid = ref('')const handleClick = () => {console.log('click')
}const tableData = ref([])
onMounted(()=>{http.get('role/').then(res=>{tableData.value = res.data.dataconsole.log(res.data.data);})
})const setres=(rid)=>{roleid.value = ridhttp.get('resource/?roleid='+rid).then(res=>{data.value = res.data.allresvalue.value = res.data.checkedidsdialogVisible.value=trueconsole.log(res.data.allres);console.log(res.data.checkedids);})}const addresource=()=>{http.post('resource/',{'roleid':roleid.value,'resids':value.value}).then(res=>{roleid.value=''dialogVisible.value=false})
}
</script>

d.页面效果

在这里插入图片描述

2.登录时获取对应权限

a.员工登录

课程模块分类管理课程管理
接口权限表:资源id(manytomany)、接口地址2				/cates/3				/courses/3				/cates/

手机号—>验证通过后获取roleid,通过roleid获取资源列表,把资源列表返回给前端
eg:[{"id":1,"name":"课程模块","sons":[{"id":2,"name":"分类管理",'url':""}]}]
查询资源对应的接口权限列表,存入redis

# 账号密码登录
class LoginView(APIView):def post(self, request):# 获取参数# username = request.data.get('username', None)# password = request.data.get('password', None)phone = request.data.get('phone', None)# 验证码# ...# 查询user表print(phone)user = UserModel.objects.filter(phone__exact=phone).first()reso = user.role.resource.all()# 构建父类资源/资源信息重组、rlist = []idlist = []interlist=[] #接口权限列表for i in reso:# 获取此资源的所有接口interfaces = i.interfaces.all()for interface in interfaces:interlist.append(interface.url)pid = i.pid.idif pid not in idlist:rlist.append({"id":pid,"name":i.pid.name,'son':[]})idlist.append(pid)# 遍历rlistfor index,i in enumerate(rlist):#遍历resfor j in reso:# 找到父类的sonif j.pid.id == i['id']:rlist[index]['son'].append({"id":j.id,'name':j.name,'url':j.url})print("rlist--->")print(rlist)# 查询资源对应的接口权限列表,存入redisr.set_str('user'+str(user.id)+'interface',json.dumps(interlist))# if not user:#     return Response({"code":"2001",'message': 'User not found'})# if password != user.password:#     return Response({"code":"2002",'message': 'Wrong password'})token = mjwt.jwt_encode({"userid":user.id,'exp':int(time.time())+3600})return Response({"code":"200",'message': 'Successfully logged in',"token":token,"rlist":rlist})

b.中间件

中间件:
token 是否存在、是否过期、是否退出
从token中解析出userid,根据userid查询接口权限列表,查询redis
request.path not in reslist:

class PermitionMiddleware(MiddlewareMixin):def process_request(self, request):# 1.定义白名单,在登录前需要操作的接口放到白名单中wlist = ['/register/', '/login/', '/sendsms/']# 获取当前的urlpath = request.pathprint("middleware---------------------------1")print(path)# 2.如果不在白名单,获取token,验证if path not in wlist:print("middleware----------------------------2")try:token = request.headers.get('Authorization')data = mjwt.jwt_decode(token)except:return JsonResponse({"code": 401, "mes": "token不存在或者被修改"})# data没问题 ↓exp = int(data['exp'])now = int(time.time())userid = data['user_id']request.userid = userid# 判断是否过期if now > exp:return JsonResponse({"code": 401, "mes": "token已经过期不能操作"})#是否退出,退出时存tokenvalue = r.get_str(token)if value:return JsonResponse({"code": 401, "mes": "用户已经退出,不能操作"})# 3.↑↑↑验证是否被修改,是否过期,是否已经退出 (点击退出,把token存入redis, 加一个过期时间),任何一个问题,return 401没有权限操作,通过继续下一步操作#验证是否有权限操作接口list = r.get_str('user'+str(userid)+'interface')if list:list = json.loads(list)if path not in list:return JsonResponse({"code":401,"mes":"没有操作此接口的权限"})

c.前端请求

登录请求

    fnLogin() {// alert("登录")http.post("http://localhost:8000/login/",{phone:this.user.phone,password:this.user.password}).then((result) => {console.log(result.data.rlist);if (result.data.code == '200') {alert(result.data.message)// 资源列表localStorage.setItem('rlist',JSON.stringify(result.data.rlist))// 用户 tokenlocalStorage.setItem('token',result.data.token)// localStorage.setItem("phone",this.user.phone)// localStorage.setItem('menulist',JSON.stringify(result.data.menulist))// this.$router.push('/index')this.$router.push('/home')} else {alert(result.data.message)}}).catch((err) => {alert(err)});}

d.效果图

登录成功后,跳转到home页面,展示当前用户所具有的功能模块
List2为当前用户所配置的资源模块
在这里插入图片描述
展示用户所具有的资源模块
在这里插入图片描述

3.前端-路由守卫-页面权限

1.login接口返回menulist
2.vue页面调用登录接口
3.路由守卫

// 导航守卫
router.beforeEach((to, from, next) => {var reslist = ['/login', '/register', '/home', '/', '/chat']if (reslist.indexOf(to.path) == -1) {var token = localStorage.getItem('token')if (token) {//验证是否在权限列表中// var menulist = localStorage.getItem('menulist');var menulist = localStorage.getItem('rlist');// var mlist = JSON.parse(menulist)var mlist: any[] = menulist ? JSON.parse(menulist) : [];console.log("milist-------");console.log(mlist);if (mlist.indexOf(to.path) >= 0) {next()} else {alert("无权访问此页面")next({ "name": '/' })}} else {next({ "name": 'Login' })}}//对于登录、注册、首页等不需要权限的页面,直接放行next()})

三、拓展

  • rbac0 基础
    • 四张表
  • rbac1 角色继承
    • 基础角色–>配置资源
    • 角色->继承基础角色
    • 角色表:id、name、pid
  • rbac2 资源互斥
考试系统、比赛系统1	  考试2	  打分互斥表
res1	res21		  2
  • rbac3 继承+互斥
  • 位运算优化权限系统
    • 添加权限 | 对比权限& 删除权限^

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

鸿蒙HarmonyOS开发:如何灵活运用动画效果提升用户体验

文章目录 一、动画概述1、动画的目的 二、显式动画 (animateTo)1、接口2、参数3、AnimateParam对象说明4、示例5、效果 三、属性动画 (animation)1、接口2、参数3、AnimateParam对象说明4、系统可动画属性4、示例5、效果 一、动画概述 动画的原理是在一个时间段内&#xff0c;…

IDEA缓存和索引

IDEA缓存和索引 —2020年06月10日 IntelliJ IDEA首次加载项目的时候。都会创建索引&#xff0c;而创建索引的时间根项目的文件多少成正比。 IntelliJ IDEA的缓存和索引主要是用来加快文件查询&#xff0c;从而加快各种查找、代码提示等操作的速度。 某些特殊情况下&#xf…

剑和沙盒 1 - Windows Sandbox 简介

Windows Sandbox 提供了一个轻量级桌面环境&#xff0c;可以安全地独立运行应用程序。安装在 Windows Sandbox 环境中的软件仍处于“沙盒”状态&#xff0c;独立于主机运行。 沙盒是临时的。关闭后&#xff0c;所有软件、文件和状态都会被删除。每次打开应用程序时&#xff0c…

scrapy 爬取旅游景点相关数据(一)

第一节 Scrapy 练习爬取穷游旅游景点 本项目为scrapy 练手项目&#xff0c;爬取的是穷游旅游景点列表数据 0 系统的环境 现在网上可以找到很多scrapy版本的视频或者代码&#xff0c;为避免混淆&#xff0c;下面列出本文开发过程中使用的软件版本。 scrapy 和 selenium 新版本和…

【NPU 系列专栏 3.1 -- - NVIDIA 的 Orin 和 Altan 和 Thor 区别】

请阅读【嵌入式及芯片开发学必备专栏】 文章目录 NVIDIA Orin、Altan 和 ThorNVIDIA Orin 简介NVIDIA Orin 主要特点NVIDIA Orin 应用场景 NVIDIA Altan 简介NVIDIA Altan 主要特点NVIDIA Altan 应用场景 NVIDIA Thor 简介NVIDIA Thor 主要特点NVIDIA Thor 应用场景 与 Hopper …

重生之“我打数据结构,真的假的?”--5.堆(无习题)

1.堆的概念与结构 如果有⼀个关键码的集合 &#xff0c;把它的所有元素按完全⼆叉树的顺序存储⽅ 式存储&#xff0c;在⼀个⼀维数组中&#xff0c;并满⾜&#xff1a; &#xff08; 且 &#xff09;&#xff0c; i 0、1、2... &#xff0c;则称为⼩堆(或⼤堆)。将根结点最⼤的…

【数组中的 k-diff 数对】python刷题记录

R2-哈希表。 有点easy的感觉 class Solution:def findPairs(self, nums: List[int], k: int) -> int:#查找对的方式是查找xk&#xff0c;不查找x-k是避免查找重复#此外&#xff0c;需要注意k0的问题mp{}for x in nums:if x in mp:mp[x]1else:mp[x]1ret0for x,cnt in mp.ite…

2024年7月25日(Git gitlab以及分支管理 )

分布式版本控制系统 一、Git概述 Git 是一种分布式版本控制系统,用于跟踪和管理代码的变更。它是由Linus Torvalds创建的,最 初被设计用于Linux内核的开发。Git允许开发人员跟踪和管理代码的版本,并且可以在不同的开 发人员之间进行协作。 Github 用的就是Git系统来管理它们的…

C++内存管理和模板/stl初识

前言 c兼容C语言&#xff0c;但它因为有类和对象的概念&#xff0c;C语言原生的那套内存管理函数在特定场景下还是有些捉襟见肘的&#xff0c;为此c在C语言的基础上引入新的内存管理方案&#xff0c;今天我们就来简单的认识一下c的内存管理。除此之外&#xff0c;模板也是c引入…

数据结构与算法——赫夫曼编码

1、基本介绍 &#xff08;1&#xff09;赫夫曼编码也翻译为 哈夫曼编码(Huffman Coding)&#xff0c;又称霍夫曼编码&#xff0c;是一种编码方式。属于一种程序算法。赫夫曼编码是赫夫曼树在电信通讯中经典的应用之一。 &#xff08;2&#xff09;赫夫曼编码被广泛地应用于数据…

C语言程序设计13

程序设计13 问题13_1代码13_1结果13_1 问题13_2代码13_2结果13_2 问题13_3代码13_3结果13_3 问题13_1 函数 f u n fun fun 的功能是&#xff1a;把形参 s s s 所指字符串中下标为奇数的字符右移到下一个奇数位置&#xff0c;最右边被移出字符串的字符绕回放到第一个奇数位置&…

77.WEB渗透测试-信息收集-框架组件识别利用(1)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;76.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;16&#xff09; java&#xff…

Cannot access org.springframework.context.ConfigurableApplicationContext

Cannot access org.springframework.context.ConfigurableApplicationContext SpringApplication.run曝红 解决方案&#xff1a; File -> Invalidate Cache and Restart 如果对你有用就点个赞&#xff01;

FPGA开发——奇数分频器的设计

一、概论 在我们进行FPGA分频器的学习当中&#xff0c;我们通常会学习怎样完成任意分频器的设计&#xff0c;其中就包括偶数分频最为常见。在实现的分频器的同时我们也会不定时的要求同时设置对应的占空比。今天我们就来看看怎样同时设置奇数分频器和其对应50%的占空比。 二、…

LabVIEW操作系列1

系列文章目录 我的记录&#xff1a; LabVIEW操作系列 文章目录 系列文章目录前言五、特殊用法5.1 取值范围表示5.2 对输入值取值范围进行限定5.3 控制多个While循环停止运行。5.4 获取按钮上的文本5.5 获取按钮上的文本【进阶】 六、使用步骤1.引入库2.读入数据 七、其余功能7.…

机器学习笔记——决策树

定义 决策树是一种可以用来解决回归和分类的问题的算法 决策树使用树形结构&#xff0c;通过叶子节点上的条件层层推理&#xff0c;得到最终的结果 例如&#xff1a;通过上面的简单决策&#xff0c;我们可以通过形状这一条件决策出水果属于哪一类。 决策树的学习结果和取什么规…

RK3588+MIPI+GMSL+AI摄像机:自动车载4/8通道GMSL采集/边缘计算盒解决方案

RK3588作为目前市面能买到的最强国产SOC&#xff0c;有强大的硬件配置。在智能汽车飞速发展&#xff0c;对图像数据矿场要求越来越多的环境下&#xff0c;如何高效采集数据&#xff0c;或者运行AI应用&#xff0c;成为刚需。 推出的4/8通道GMSL采集/边缘计算盒产品满足这些需求…

鸿蒙(HarmonyOS)自定义Dialog实现时间选择控件

一、操作环境 操作系统: Windows 11 专业版、IDE:DevEco Studio 3.1.1 Release、SDK:HarmonyOS 3.1.0&#xff08;API 9&#xff09; 二、效果图 三、代码 SelectedDateDialog.ets文件/*** 时间选择*/ CustomDialog export struct SelectedDateDialog {State selectedDate:…

解开基于大模型的Text2SQL的神秘面纱

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

环境搭建-Windows系统搭建Docker

Windows系统搭建Docker 一、系统虚拟化1.1 启用虚拟化2.2 启用Hyper-v并开启虚拟任务 三、安装WSL3.1 检验安装3.2 安装WSL 四、Docker安装4.1 Docker安装包下载4.2 Docker安装4.3 运行docker Desktop 五、Docker配置5.1 打开Docker配置中心5.2 配置Docker国内镜像 六、使用 一…