django用户权限管理(Django 内置权限扩展案例详解)
django用户权限管理
Django 内置权限扩展案例详解当django的内置权限无法满足需求的时候就自己扩展吧~
背景介绍
overmind项目使用了django内置的权限系统,django内置权限系统基于model层做控制,新的model创建后会默认新建三个权限,分别为:add、change、delete,如果给用户或组赋予delete的权限,那么用户将可以删除这个model下的所有数据。
原本overmind只管理了我们自己部门的数据库,权限设置只针对具体的功能不针对细粒度的数据库实例,例如用户a 有审核的权限,那么用户a 可以审核所有的db,此时使用内置的权限系统就可以满足需求了,但随着系统的不断完善要接入其他部门的数据库管理,这就要求针对不同用户开放不同db的权限了,例如a部门的用户只能操作a部门的db,django内置基于model的权限无法满足需求了。
实现过程
先来确定下需求:
1. 保持原本的基于功能的权限控制不变,例如用户a有查询权限,b有审核权限
2. 增加针对db实例的权限控制,例如用户a只能查询特定的db,b只能审核特定的db
对于上边需求1用内置的权限系统已经可以实现,这里不赘述,重点看下需求2,db信息都存放在同一个表里,不同用户能操作不同的db,也就是需要把每一条db信息与有权限操作的用户进行关联,为了方便操作,我们考虑把db跟用户组关联,在用户组里的用户都有权限,而操作类型经过分析主要有两类读和写,那么需要给每个mysql实例添加两个字段分别记录对此实例有读和写权限的用户组
如下代码在原来的model基础上添加 read_groups
和 write_groups
字段,db实例跟用户组应是manytomanyfield多对多关系,一个实例可以关联多个用户组,一个用户组也可以属于多个实例
|
class mysql(models.model): env = ( ( 1 , 'dev' ), ( 2 , 'qa' ), ( 3 , 'prod' ), ) create_time = models.datetimefield(auto_now_add = true, verbose_name = '创建时间' ) update_time = models.datetimefield(auto_now = true, verbose_name = '更新时间' ) project_id = models.integerfield(verbose_name = '项目' ) project_tmp = models.charfield(max_length = 128 , default = '') environment = models.integerfield(choices = env, verbose_name = '环境' ) master_host = models.genericipaddressfield(verbose_name = 'master主机' ) master_port = models.integerfield(default = 3306 , verbose_name = 'master端口' ) slave_host = models.genericipaddressfield(null = true, verbose_name = 'slave主机' ) slave_port = models.integerfield(null = true, default = 3306 , verbose_name = 'slave端口' ) database = models.charfield(max_length = 64 , verbose_name = '数据库' ) read_groups = models.manytomanyfield(group, related_name = 'read' , verbose_name = '读权限' ) write_groups = models.manytomanyfield(group, related_name = 'write' , verbose_name = '写权限' ) description = models.textfield(null = true, verbose_name = '备注' ) |
model确定了,接下来我们分三部分详细介绍下权限验证的具体实现
列表页权限控制
如上图列表页,每个用户进入系统后只能查看自己有读权限的mysql实例列表,管理员能查看所有,代码如下:
|
def mysql(request): if request.method = = 'get' : if request.user.is_superuser: _lists = mysql.objects. all ().order_by( 'id' ) else : # 获取登录用户的所有组 _user_groups = request.user.groups. all () # 构造一个空的queryset然后合并 _lists = mysql.objects.none() for group in _user_groups: _lists = _lists | group.read. all () return render(request, 'overmind/mysql.index.html' , { 'request' : request, 'lpage' : _lists}) |
实现的思路是:获取登录用户的所有组,然后循环查询每个组有读取权限的数据库实例,最后把每个组有权限读的数据库实例进行合并返回
获取登录用户的所有组用到了manytomany的查询方法: request.user.groups.all()
最终返回的一个结果是queryset,所以我们需要先构造一个空的queryset: mysql.objects.none()
queryset合并不能用简单的相加,应为: queryset-1 | queryset-2
查询接口权限控制
如上图系统中有很多功能是需要根据项目、环境查询对应的db信息的,对于此类接口也需要控制用户只能查询自己有权限读的db实例,管理员能查看所有,代码如下:
|
def get_project_database(request, project, environment): if request.method = = 'get' : _jsondata = {} if request.user.is_superuser: # 返回所有项目和环境匹配的db _lists = mysql.objects. filter ( project_id = int (project), environment = int (environment) ) _jsondata = {i. id : i.database for i in _lists} else : # 只返回用户有权限查询的db _user_groups = request.user.groups. all () for group in _user_groups: # 循环mysql表中有read_groups权限的所有组 for mysql in group.read. all (): if mysql.project_id = = int (project) and mysql.environment = = int (environment): _jsondata[mysql. id ] = mysql.database return jsonresponse(_jsondata) |
实现思路与上边类似,只是多了一步根据项目和环境再进行判断
需要根据group去反查都有哪些db实例包含了该组,这里用到了m2m的related_name属性: group.read.all()
更多关于django orm查询的内容可以看这篇文章 django model select的各种用法详解 有详细的总结
执行操作权限控制
除了上边的两个场景之外我们还需要在执行具体的操作之前去判断是否有权限,例如执行审核操作前判断用户是否对此db有写权限
有很多地方都需要做这个判断,所以把这个权限判断单独写个方法来处理,代码如下:
|
def check_permission(perm, mysql, user): # 如果用户是超级管理员则有权限 if user.is_superuser: return true # 取出用户所属的所有组 _user_groups = user.groups. all () # 取出mysql对应权限的所有组 if perm = = 'read' : _mysql_groups = mysql.read_groups. all () if perm = = 'write' : _mysql_groups = mysql.write_groups. all () # 用户组和db权限组取交集,有则表示有权限,否则没有权限 group_list = list ( set (_user_groups).intersection( set (_mysql_groups))) return false if len (group_list) = = 0 else true |
实现思路是:根据传入的第三个用户参数,来获取到用户所有的组,然后根据传入的第一个参数类型读取或写入和第二个参数db实例来获取到有权限的所有组,然后对两个组取交集,交集不为空则表示有权限,为空则没有
m2m的 .all()
取出来的结果是个list,两个list取交集的方法为: list(set(list-a).intersection(set(list-b)))
view中使用就很简单了,如下:
|
def query(request): if request.method = = 'post' : postdata = request.body.decode( 'utf-8' ) _host = get_object_or_404(mysql, id = int (postdata.get( 'database' ))) # 检查用户是否有db的查询权限 if check_permission( 'read' , _host, request.user) = = false: return jsonresponse({ 'state' : 0 , 'message' : '当前用户没有查询此db的权限' }) |
写在最后
1. django有第三方的基于object的权限管理模块django-guardian,本项目没有使用主要是因为一来权限需求并不复杂,自己实现也很方便,二来个人在非必要的情况下并不喜欢引用过多第三方的包,后续升级维护都是负担
2. 方案和代码不尽完美,各位有更好的方案建议或更优雅的代码写法欢迎与我交流
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持开心学习网。
原文链接:https://mp.weixin.qq.com/s?__biz=MzU5MDY1MzcyOQ==&mid=2247483944&idx=1&sn=fed70b8c31b7a7a3dc2ae1d9f2d0596f&scene=21#wechat_redirect
- MVC扩展HtmlHelper实现CheckBoxList
- 解忧大队es6扩展运算符(ES6扩展运算符的使用方法示例)
- vue3中的setup的参数(Vue3中ref与reactive的详解与扩展)
- dedecms中的有些功能如何修改(DEDECMS 扩展标签和dede自定义标签实现方法)
- C# 扩展方法
- javascript数组实例扩展方法(JavaScript如何监测数组的变化)
- amaze算法(amazeui 验证按钮扩展的实现)
- phpmysql怎么搭建(PHP使用PDO、mysqli扩展实现与数据库交互操作详解)
- django用户权限管理(Django 内置权限扩展案例详解)
- php7用什么替代mysql(mysqli扩展无法在PHP7下升级问题的解决)
- php 创建定时任务(PHP扩展Swoole实现实时异步任务队列示例)
- php7处理方案(PHP7 安装event扩展的实现方法)
- linux虚拟主机怎么设置(linux系统虚拟主机开启支持Swoole Loader扩展的方法)
- chrome适合开发的插件(Chrome插件扩展开发全攻略完整demo)
- access区分登录身份的代码(妙用.htaccess隐藏网页文件扩展名)
- python3循环使用教程(Python3.4学习笔记之 idle 清屏扩展插件用法分析)
- 盘古开天地 他创造了世界,谁创造了盘古 盘古是伏羲吗(盘古开天地他创造了世界)
- 关于队徽 你了解这些么 二(关于队徽你了解这些么)
- 冬天来了手脚冰凉 真不是因为上辈子你是折翼的天使(冬天来了手脚冰凉)
- 0 1 岁婴儿最强作息指南,照着做养出天使宝宝(01岁婴儿最强作息指南)
- 沪上这16所高校 萌新 礼包开箱 哪一款让你心动(沪上这16所高校萌新)
- 她救了被绑架的他,而这一切竟是一场阴谋...(她救了被绑架的他)
热门推荐
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9