`

django guardian 对象级别权限设计

阅读更多

         django 目前权限两种:

             1.表级别,也是model,默认的表级别,add ,delete,change

             2.对象级别,也是field

 

        虽加入了guardian,设计思路还是user ,group,role,类似于linux的3 2 1

 

        guradian 的官网示例

       https://django-guardian.readthedocs.io/en/stable/userguide/assign.html#prepare-permissions

 

       常用的示例:

       

Django实现Object级别的权限控制-django-guardian

在我的系列blog《Django中内置的权限控制》中明确提及到,Django默认并没有提供对Object级别的权限控制,而只是在架构上留了口子。在这篇blog中,我们探讨一个简单流行的Django组件django-guardian来实现Object level permission。

安装配置django-guardian

首先需要安装django-guardian,一般我们喜欢用virtualenv创建一个虚拟环境:

>>virtualenv --distribute venv
>>source venv/bin/activate
>>pip install Django
>>pip install django-guardian

 这样,我们需要的django-guardian 就安装好了。

接下来我们需要让Django知道它,在INSTALLED_APPS变量中加入guardian:

INSTALLED_APPS = (
    'guardian',
)

然后,如果仔细读过《Django中内置的权限控制》的第五篇文章的读者,应该猜到,我们需要添加一个backend到AUTHENTICATION_BACKENDS中,这样django才会具有对对象的权限控制:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend', # django默认的backend
    'guardian.backends.ObjectPermissionBackend',
)

在guardian中,还支持对匿名用户AnoymousUser的Object级别的权限控制,这种需求很常见,比方说允许匿名发言的论坛或者blog系统。要做到这一点需要在settings中加入:

ANONYMOUS_USER_ID=-1

接下来我们执行python manage syncdb.执行完毕之后,系统将会创建一个User实例,叫做AnonymouseUser。

完成了以上几点,guardian就被安装好了,可以开始使用了。

 设置和使用对象权限:

首先当然是设置和使用对象权限了,guardian提供了一个简单的方法:

guardian.shortcuts.assign(perm, user_or_group, obj=None),这个方法接受3个参数:

  1. perm,这个参数是一个字符串,代表一个许可,格式必须为<app>.<perm_codename>或者<perm_codename>。但是如果第三个参数是None,则必须为<app>.<perm_codename>格式。因此建议还是统一使用<app>.<perm_codename>格式。注意app并不是app的全路径,而是最后一级的模块名。这一点和INSTALL_APP中的app全路径不同,如果你的app module不只一级的话,这地方一定要注意。
  2. user_or_group,这个参数是一个User或者Group类型的对象。
  3. obj,这个参数就是相关的对象了。改参数是可省略的,如果省略则赋予Model权限。

通过这个方法我们可以很方便通过传入一个<app>.<perm_codename>格式的字符串来给用户User或组Group赋予权限了。如果不传入第三个参数,则可以当作User.user_permissions.add(permissioninstance) 的快捷方式。

下面是赋予模型级别的权限:

from guardian.shortcuts import assign
user = User.objects.create(username='liuyong')
assign('app.view_task', user)
user.has_perm('app.view_task') >>True

注意,一旦赋予模型级的权限,那么所有该模型的对象级别的权限就都有了,所以应该先从对象级别进行设置,清空刚刚分配的权限然后再设置对象权限:

user = User.objects.get(username='liuyong')
user.user_permissions.clear()
task = Task.objects.create(summary='Some job', content='')
assign('app.view_task', user, task)
user = User.objects.get(username='liuyong')#刷新缓存
user.has_perm('app.view_task',task)
>>True
user.has_perm('app.view_task')#模型级别的权限还没有
>>False

我们也可以通过设置group来使用户具有相应的权限:

>>> group = Group.objects.create(name='employees')
>>> assign('change_task', group, task)
>>> user.has_perm('change_task', task)
False
>>> # user还不是employees组的成员,我们加入一下
>>> user.groups.add(group)
>>> user.has_perm('change_task', task)
True

接下来是删除某个用户对某个对象的某种许可,我们需要使用guardian.shortcuts模块中的remove_perm()函数。这个函数的签名和assign相同,都是三个:

guardian.shortcuts.remove_perm(perm,user_or_group=None, obj=None)

样例代码:

1
2
3
4
5
>>> from guardian.shortcuts import remove_perm
>>> remove_perm('change_site', user, site)
>>> user = User.objects.get(username='joe'#刷新user对象缓存
>>> joe.has_perm('change_site', site)
False

  

 好上面就是guadian的安装配置和基本使用方法,下面介绍在Django的View中所能使用的一些helper函数。

Guardian在View中的使用

除了Django的user.has_perm方法之外,guardian提供了一些帮助函数能让我们生活的更轻松。

guardian.shortcuts.get_perms(user_or_group,obj)

该方法返回user对象对obj对象所有的权限。这个行数接受两个参数,一个是user对象或者组对象,一个是相关的对象。

比如我们可以用:

'permcodename' in get_perms(group,obj)来判断该组是否有这个权限,因为group没有has_perm方法。

guardian.shortcuts.get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=False)

该函数获得该用户下指定perm列表中的所有对象。比如我要获得某一个用户,拥有编辑权限的所有帖子。

get_objects_for_user(user,'app.change_post')
>>所有可编辑的帖子

guadian.core.ObjectPermissionChecker

该方法是一个用来判断权限的包装器,针对user和group提供权限相关的访问方法,主要有has_perm(perm,obj)和get_perms(obj)两个方法。并且提供缓存机制,在多次查找权限的时候,可以使用它。

>>> epser = User.objects.get(username='esper')
>>> site = Site.objects.get_current()
>>> from guardian.core import ObjectPermissionChecker
>>> checker = ObjectPermissionChecker(esper) # 我们也可以传入组group对象
>>> checker.has_perm('change_site', site)
True
>>> checker.has_perm('add_site', site) # 这次将不会产生数据库查询
False
>>> checker.get_perms(site)
[u'change_site']

使用view的decorator

我们可以使用decorator来减少我们的代码:

下面的代码,演示了通过decorator控制一个view函数的访问。我们要做到的是,只有拥有对name=foobars的Group对象拥有auth.change_group权限的用户,才能够执行这个view函数,否则返回的将是状态码为403的Response对象。

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
26
27
28
>>> joe = User.objects.get(username='joe')
>>> foobars = Group.objects.create(name='foobars')
>>>
>>> from guardian.decorators import permission_required_or_403
>>> from django.http import HttpResponse
>>>
>>> @permission_required_or_403('auth.change_group',
>>>     (Group, 'name''group_name'))
>>> def edit_group(request, group_name):
>>>     return HttpResponse('some form')
>>>
>>> from django.http import HttpRequest
>>> request = HttpRequest()
>>> request.user = joe
>>> edit_group(request, group_name='foobars')
<django.http.HttpResponseForbidden object at 0x102b43dd0>
>>>
>>> joe.groups.add(foobars)
>>> edit_group(request, group_name='foobars')
<django.http.HttpResponseForbidden object at 0x102b43e50>
>>>
>>> from guardian.shortcuts import assign
>>> assign('auth.change_group', joe, foobars)
<UserObjectPermission: foobars | joe | change_group>
>>>
>>> edit_group(request, group_name='foobars')
<django.http.HttpResponse object at 0x102b8c8d0>
>>> # 这时,我们已经分配了权限,因此我们的view方法得以顺利访问了。

Guardian在模版中的使用 

 和Django一样,我们也需要在界面上进行权限控制以显示不同的界面。

Guardian提供了标签:

get_obj_perms

需要加载guardian_tags标签库,在需要使用guardian标签的模版上面,将其引用近来:

{% load guardian_tags %}

标签格式为:

{% get_obj_perms user/group for obj as "context_var" %}

例子代码如下:

{% get_obj_perms request.user for flatpage as "flatpage_perms" %}
 
{% if "delete_flatpage" in flatpage_perms %}
    <a href="/pages/delete?target={{ flatpage.url }}">Remove page</a>
{% endif %}

 

下面探讨一下稍微复杂一些的情况,关于孤儿对象许可(Orphaned object permissions):

 孤儿对象许可

所谓孤儿许可,就是没用的许可。在大多数情况下,可能没啥事儿,但是一旦发生,后果有可能非常严重。

Guardian用来纪录某用户对某个模型对象有某个权限的纪录时是使用UserObjectPermission和GroupObjectPermission对象纪录的。其中对于object的引用是contenttype对象(标示是那个模型类)和pk主键,对于用户则是对User表的外键引用。

比方说,有一个对象A。我们通过权限设置,设定joe用户对该对象有着编辑权限。忽然有一天,用户joe被删除了。可想而知,我们分配而产生的UserObjectPermission对象仍然在数据库里面,记录着:joe 有对A的编辑权限。又有一天,一个用户注册了一个用户,用户username为joe。因为之前的那个纪录,joe用户拥有对A的编辑权限。而此joe非彼joe,我们犯了一个大错误!

再比如说,当我们删除了某一个对象的时候,而这个对象的某种权限已经被赋予给某个用户,那么这个权限的纪录也就失效了。如果什么时候和曾经删除过的对象是同一个模型类,而且主键和以前的那个相同,那么用户也就有可能对其本不应该拥有权限的对象有了权限。呵呵,说起来有点绕,但是应该很容易理解。

因此,当我们删除User和相关的Object的时候,我们一定要删除其相关的所有UserObjectPermission和GroupObjectPermission对象。

要解决这个办法有三个办法,一个是显式编码,一个是通过其提供的自定义django命令:

1
2
$ python manage.py clean_orphan_obj_perms
Removed 11 object permission entries with no targets

还有一个是定期调用guardian.utils.clean_orphan_obj_perms()

该函数会返回删除的对象数目。在python的世界中,我们可以使用celery定期调度这个任务。

但是自定义命令和定期调度都不是合理的生产环境的解决办法。要想真正解决,还是需要手动编码实现,最优雅的方式还是加上post_delete signal给User或Object对象,关于对象的样例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.db.models.signals import pre_delete
from guardian.models import UserObjectPermission
from guardian.models import GroupObjectPermission
from school.models import StudyGroup
 
 
def remove_obj_perms_connected_with_user(sender, instance, **kwargs):
    filters = Q(content_type=ContentType.objects.get_for_model(instance),
        object_pk=instance.pk)
    UserObjectPermission.objects.filter(filters).delete()
    GroupObjectPermission.objects.filter(filters).delete()
 
pre_delete.connect(remove_obj_perms_connected_with_user, sender=StudyGroup)

 

0
0
分享到:
评论
1 楼 hsluoyz 2019-05-22  
PyCasbin 是一个用 Python 语言打造的轻量级开源访问控制框架( https://github.com/casbin/pycasbin ),支持ACL、RBAC、ABAC、Restful等权限模型,目前在 GitHub 开源。针对Django可以采用Django-Casbin权限插件:https://github.com/pycasbin/django-casbin

相关推荐

    基于Django和Guardian的用户权限管理设计源码

    本资源提供了一套基于Django和Guardian的用户权限管理设计源码,包含173个文件,其中包括76个Python源代码文件,33个ReST文档文件,26个HTML页面文件,以及7个MO翻译文件和7个PO翻译文件。此外,还包括4个Shell脚本...

    使用django-guardian实现django-admin的行级权限控制的方法

    从上述代码片段中可以看出,GuardedModelAdmin类提供了编辑对象权限的按钮,并且需要对get_queryset方法进行重写,以确保非超级用户只能看到他有权限的记录。需要自定义的函数还可能包括assign_perm、remove_perm等...

    Python-djangoguardianDjango12实现了单个对象权限

    **Python-djangoguardianDjango1.2实现了单个对象权限** 在Django框架中,权限管理是至关重要的一个部分,它确保只有授权的用户或组能够访问特定的资源。默认情况下,Django提供了基于类的权限系统,即对模型级别的...

    django-guardian:Django的每个对象权限

    django-guardian是基于Django授权后端的按对象权限的实现。 文献资料 在线文档位于 。 要求 Python 3.5+ 受支持的Django版本(当前为2.2+) GitHub Actions针对Django 2.2、3.0、3.1、3.2和main版本运行测试。 ...

    django-guardian:Django 1.2+ 实现了单个对象权限-python

    django-guardian:Django 1.2+ 实现了单个对象权限 django-guardian django-guardian 是每个对象权限 [1] 作为授权后端的实现,自 Django 1.5 起支持。 它不适用于较旧的 Django 版本。 文档 在线文档可在 ...

    Django的每个对象权限-Python开发

    django-guardian django-guardian是每个对象权限[1]的实现,它是自Django 1.5开始受支持的授权后端。 它不适用于较早的Django版本。 文档在线文档django-guardian django-guardian是基于对象的权限[1]在Django授权...

    PyPI 官网下载 | django-guardian-1.0.3.tar.gz

    django-guardian-1.0.3.tar.gz是一个包含源代码的压缩包,用于在Django项目中实现对象级别的权限管理。开发者可以下载此包,解压后通过pip安装到Python环境中,并在Django项目中配置和使用,以实现更精细的用户访问...

    django-guardian

    django-guardian是每个对象权限作为授权后端的实现,自 1.2 起支持。 它不适用于较旧的版本。 文献资料 联机文档可从以下网站获得: 或 安装 要安装django-guardian只需运行: pip install django-guardian 配置 ...

    基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计)

    基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计),基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计),基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计)...

    基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计).zip

    基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计),基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计),基于python+django学生信息管理系统设计与实现(含程序源码和毕业设计)...

    基于django的管理系统的设计与实现.zip

    基于django的管理系统基于django的管理系统的设计与实现.zip基于django的管理系统的设计与实现.zip基于django的管理系统的设计与实现.zip基于django的管理系统的设计与实现.zip基于django的管理系统的设计与实现.zip...

    课程设计基于Vue3和Django实现的rbac权限管理系统python源码(含前端)+项目说明.zip

    【资源说明】课程设计基于Vue3和Django实现的rbac权限管理系统python源码(含前端)+项目说明.zip在线预览[https://xadmin.dvcloud.xin/](https://xadmin.dvcloud.xin/)账号密码:admin/admin123生成数据表并迁移```...

    Python-djangorules一个小巧但是强大的应用提供对象级别的权限管理且不需要使用数据库

    总结来说,`django-rules`是Django框架下对象级别权限管理的一个优秀选择,它以简洁的方式扩展了Django的权限模型,无需数据库存储,易于维护,且功能强大。在实际开发中,结合使用`rules`可以更好地保护数据安全,...

    django笔记 django笔记

    Django拥有丰富的第三方库,如Django REST framework用于构建RESTful API,Django Channels支持WebSocket通信,以及用于权限管理的Django Guardian等。 以上只是Django框架的基本介绍,实际上,Django的功能远不止...

    一种基于Vue.js和Django的权限控制方法及系统.pdf

    Django的权限系统可以通过模型级别的权限、视图级别的权限以及自定义的权限检查来实现这一目标。当前端发送请求到后端时,Django会检查请求的合法性,只有满足权限条件的请求才会被处理。 此外,该发明还可能包含一...

    基于django的RBAC权限控制模块

    1. **模型设计**:在Django中,模型是数据库表的抽象,用于定义数据结构。在RBAC系统中,我们需要创建`User`、`Role`和`Permission`模型。`User`模型通常继承自Django内置的`AbstractBaseUser`或`AbstractUser`,以...

    计算机专业-毕业设计:基于Python+Django的博客系统的设计与实现.zip

    计算机专业—毕业设计:基于Python+Django的博客系统的设计与实现 计算机专业—毕业设计:基于Python+Django的博客系统的设计与实现 计算机专业—毕业设计:基于Python+Django的博客系统的设计与实现 计算机专业—...

    基于Django和Vue的RBAC权限控制后台管理系统源码

    后端基于Python的Django框架和Django REST Framework实现,前端则使用Vue.js配合ElementUI进行构建。移动端支持通过uniapp和uView框架,能够灵活发布H5和微信小程序。 技术构成: - 主要编程语言:Python - 前端...

    Python基于Django图书管理系统课程设计

    虽然系统功能不是很复杂,不过这是一个很好的学习案例,包括了常用字段的设计,比如字符串,浮点型,整型,日期型,图片型,富文本字符串型,文件型和下拉框外键关联型,囊括了所有商业项目设计需要的字段类型,通杀...

Global site tag (gtag.js) - Google Analytics