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_groupswrite_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确定了,接下来我们分三部分详细介绍下权限验证的具体实现

列表页权限控制

8fqkJd2s8HJjQAAAAASUVORK5CYII=

如上图列表页,每个用户进入系统后只能查看自己有读权限的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

查询接口权限控制

A9upb9Dm1JoCAAAAAElFTkSuQmCC

如上图系统中有很多功能是需要根据项目、环境查询对应的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.databasereturn 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. 方案和代码不尽完美,各位有更好的方案建议或更优雅的代码写法欢迎与我交流

o_scan.qrcode.png

相关文章推荐阅读:

  • Django+JWT实现Token认证
  • 我们自研的那些Devops工具

转载于:https://www.cnblogs.com/37Y37/p/10514575.html

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

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

相关文章

Java 从入门到高级学习路线

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 Java 从入门到高级学习路线《一》1.Jvm 部分Jvm 内存模型、Jvm 内存结构、Jvm 参数调优、Java 垃圾回收《二》Java 基础部分1.必须会使用…

Flutter Mac iOS 环境配置

官方文档:flutter.io/docs/get-st… 1.需要的命令行工具 bash curl git 2.x mkdir rm unzip which 2.SDK下载地址 flutter_macos_v1.0.0-stable.zip storage.googleapis.com/flutter_inf… 3.解压Flutter SDK cd ~/Flutter/SDK $ unzip ~/Downloads/flutter_macos_v…

多线程研究1

单线程: from urllib.request import urlretrieve import time import random starttime.time() fopen(E:\Python\py\web\hh.txt,r)#打开存放URL的文件 af.readlines() f.close() for i in a:brandom.randint(0,30)urlretrieve(i,%d.png%b) endtime.time() print(…

android viewpage预加载和懒加载问题

1、本人理解懒加载和预加载问题某种情况下可以归结为一类问题,下面我就说一下我遇到的预加载问题和懒加载问题及解决的相应方法: - [1 ] 预加载问题 描述:我用到了三个fragment、viewpage及tablayout实现点击切换、滑动切换。 …

大数据,且行且思

“大数据”概念于20世纪90年代被提出,最初只是对一些在一定时间内无法用传统方法进行抓取、管理和处理的数据的统称。随着时间的推移和科技的发展以及物联网、移动互联网、SNS的兴起,每年产生的数据量都以几何级数增长,《IDC Digital Univers…

IntelliJ IDEA中新建JAVA WEB项目、maven项目

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 在IntelliJ IDEA 中新建一个Web应用项目。 1、 在主界面顶部菜单栏依次“File”-"New"-"Project..." 2、在对话框中…

S/4HANA业务角色概览之订单到收款篇

2019独角兽企业重金招聘Python工程师标准>>> 大家好我叫Sean Zhang,中文名张正永。目前在S/4HANA产品研发部门任职产品经理,而这一阶段要从2017年算起,而在那之前接触更多还是技术类的,比如做过iOS、HANA、ABAP、UI5等…

掘金量化的一个代码,对本人写策略避免入坑有重要意义

# codingutf-8from __future__ import print_function, absolute_import, unicode_literalsfrom gm.api import *import numpy as npdef init(context):# 选择的两个合约context.symbol [DCE.j1901, DCE.jm1901]# 订阅历史数据subscribe(symbolscontext.symbol,frequency1d,co…

C++ STL学习笔记

C STL学习笔记一 为何要学习STL: 数据结构与算法是编程的核心,STL中包含各种数据结构和优秀的算法,确实值得深入学习,本文中虽然着重使用,但希望有心的朋友能多看看相关数据结构的实现,对于C语言确实会有较…

ItelliJ IDEA开发工具使用—创建一个web项目

转自:https://blog.csdn.net/wangyang1354/article/details/50452806概念需要明确一下IDEA中的项目(project)与eclipse中的项目(project)是不同的概念,IDEA的project 相当于之前eclipse的workspace,IDEA的M…

AKOJ-2037-出行方案

链接:https://oj.ahstu.cc/JudgeOnline/problem.php?id2037 题意: 安科的夏天真是不一般的热,避免炎热,伍学长因此想为自己规划一个校园出行方案,使得从宿舍出发到校园的各个地方距离花费时间最短。我们已知校园一共有…

akshare 布林通道策略

import datetime import pandas as pd import backtrader as bt import matplotlib.pyplot as plt from datetime import datetime import matplotlib import akshare as ak %matplotlib inline class Boll_strategy(bt.Strategy):#自定义参数,每次买入1800手param…

一些资源网站..

github上各种免费编程书籍~~~ : https://github.com/EbookFoundation/free-programming-books/blob/master/free-programming-books-zh.md正则表达式学习 :https://web.archive.org/web/20161119141236/http://deerchao.net:80/tutorials/regex/regex.htmtorch:http…

极客无极限 一行HTML5代码引发的创意大爆炸

摘要:一行HTML5代码能做什么?国外开发者Jose Jesus Perez Aguinaga写了一行HTML5代码的文本编辑器。这件事在分享到Code Wall、Hacker News之后,引起了众多开发者的注意,纷纷发表了自己的创意。 这是最初的HTML5代码,它…

c# 写文件注意问题及用例展示

以txt写string举例,正确代码如下: private void xie(){FileStream fs new FileStream("1.txt", FileMode.Create);StreamWriter sw new StreamWriter(fs, Encoding.Default);sw.Write("123");sw.Flush();sw.Close();//fs.Flush();…

akshare sma策略

import datetimeimport pandas as pdimport backtrader as bt from datetime import datetime import matplotlib import akshare as ak %matplotlib inlineclass SmaCross(bt.Strategy):# 全局设定交易策略的参数params ((pfast, 5), (pslow, 20),)def __init__(self):sma1 …

DOCKER windows 7 详细安装教程

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 DOCKER windows安装 DOCKER windows安装 1.下载程序包2. 设置环境变量3. 启动DOCKERT4. 分析start.sh5. 利用SSH工具管理6. 下载镜像 6.1…

c#UDP协议

UDP协议是不可靠的协议,传输速率快 服务器端: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;using System.Net.Sockets; using System.Net; using System.Threading;namespace…

芝麻信用免押金成趋势 报告称租赁经济有望突破10万亿元

中新网1月16日电 “很多物品都是租来的,但生活不是。”如今,越来越多的年轻人选择了“租”生活,从房子到车子,从服饰到电脑,甚至玩具、婴儿车,全都可以租用,租赁已成为当下年轻人追求品质生活的…

开发者成功学:扔掉你那些很sexy的想法

摘要:在开发者的世界里,开发iPhone应用并不像表面那么光鲜,收支不成正比是常有之事,劳心劳力开发的应用无人问津更是屡见不鲜。走出了开发的一小步却难以迈出销售推广上的一大步,究竟如何才能将应用卖出去并获取利润&a…