- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章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多对多关系,一个实例可以关联多个用户组,一个用户组也可以属于多个实例 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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实例列表,管理员能查看所有,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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实例,管理员能查看所有,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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有写权限 。
有很多地方都需要做这个判断,所以把这个权限判断单独写个方法来处理,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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中使用就很简单了,如下:
1
2
3
4
5
6
7
8
|
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 。
最后此篇关于Django 内置权限扩展案例详解的文章就讲到这里了,如果你想了解更多关于Django 内置权限扩展案例详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我对 Python-Django 和 web 开发还很陌生,我被困在这个使用 POST 创建新资源的特殊问题上。 我正在为 REST API 使用 Django REST 框架,我正在尝试创建一个新资
我已经使用 Django-storages 成功地将 Word 文档存储到 S3。 class Document(TitleSlugDescriptionModel, TimeStampedModel
我有 2 个关于模型代理的问题, 如何从模型对象创建代理对象? 如何从模型查询集创建代理查询集? 例如,假设我们定义了: from django.contrib.auth.models import
我想编写一个直接执行 HTTP 请求的单元测试(而不是使用 django.test.client.Client)。 如果您好奇为什么 - 那是因为我想测试我从 Django 应用程序公开的 Thrif
我为我的个人网站启动了一个 django 项目来学习 django。到目前为止,我已经将我的开发环境设置为我需要的一切,并遵循 this很棒的教程来创建一些基本的数据结构和模板。现在我想开始使用我之前
我已经阅读了很多关于如何在使用 Django 注册时添加额外字段的信息,例如 here 、 here 和 here 。代码片段是: forms.py(来自注册应用程序) class Registrat
我正在编写小型社交应用程序。功能之一是在网站标题中写入用户名。因此,例如,如果我登录并且我的名字是Oleg(用户名),那么我应该看到: Hello, Oleg | Click to edit prof
我有一个使用 Django 和 Django Rest 框架开发的应用程序。我想将 django-reversion 功能添加到我的应用程序中。 我已经尝试过http://django-reversi
我有一个简单的 HTML 表单,我没有使用 Django 表单,但现在我想添加一个选择。 选择最容易创建为 Django ChoiceField (与通过循环等手动创建选择相反),但是,如果没有在 D
我不明白为什么人们以两种方式编写外键,这样做的目的是什么?它们是相同还是不同? 我注意到有些人这样写: author = models.ForeignKey(Author, on_delete=mod
我想在我的 Django 应用程序中获取评论最多的十个帖子,但我做不到,因为我想不出合适的方法。 我目前正在使用 django 评论框架,并且我已经看到使用 aggregate or annotate
这对于 Django 1.2 仍然有效吗? Custom Filter in Django Admin on Django 1.3 or below 我已经尝试过,但管理类中的 list_filter
问题在于,当 django-compressor 编译为 .js 文件的 CoffeeScript 文件中引用 {{ STATIC_URL }} 时,它无法正确加载。 在我的 django 模板中,我
我正在尝试将一些字段从一个 django 模型移动到一个新模型。假设我有一个书籍模型: class Book(models.Model): title = models.CharField(max
我想在我的 Django 应用程序中获取评论最多的十个帖子,但我做不到,因为我想不出合适的方法。 我目前正在使用 django 评论框架,并且我已经看到使用 aggregate or annotate
目前我正在寻找在 Django 中实现访问控制。我已经阅读了有关内置权限的内容,但它并不关心每个对象的基础。例如,我想要“只有创建者可以删除自己的项目”之类的权限。所以我读到了 django-guar
嗨,我正在将我的 Django 模型的一个字段的值设置为其他模型的另一个字段的值。这个值应该是动态变化的。 这是我的第一个模型 class MainModel(AbstractBaseUser, Pe
我正在尝试为我的模型创建一个编辑表单。我没有使用模型表单,因为根据模型类型,用户可以使用不同的表单。 (例如,其中一个表单有 Tinymce 小部件,而另一个没有。) 有没有什么方法可以使用模型设置表
Django 模板中的搜索字段 如何在类似于此图像的 Django 模板中创建搜索字段 http://asciicasts.com/system/photos/1204/original/E354I0
根据 Django documentation ,如果 Django 安装激活了 AuthenticationMiddleware,HttpRequest 对象有一个“user”属性代表当前登录的用户
我是一名优秀的程序员,十分优秀!