django guardian 对象级别权限设计

参考地址

原文地址:https://blog.csdn.net/scdxmoe/article/details/72678005 

http://hugoren.iteye.com/blog/2363197

guradian 的官网示例:https://django-guardian.readthedocs.io/en/stable/userguide/assign.html#prepare-permissions

github: https://github.com/django-guardian/django-guardian

Django-guardian实现对象级别的权限控制:  https://cloud.tencent.com/developer/article/1444991

 

django guardian 对象级别权限设计

         django 目前权限两种:::

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

             2.对象级别,也是field

 

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

       

常用的示例:

       

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

安装配置django-guardian

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

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

INSTALLED_APPS = (
    'guardian',
)

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

ANONYMOUS_USER_ID=-1

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

 设置和使用对象权限:

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

      perm,这个参数是一个字符串,代表一个许可,格式必须为<app>.<perm_codename>或者<perm_codename>。但是如果第三个参数是None,则必须为<app>.<perm_codename>格式。因此建议还是统一使用<app>.<perm_codename>格式。

注意app并不是app的全路径,而是最后一级的模块名。这一点和INSTALL_APP中的app全路径不同,如果你的app module不只一级的话,这地方一定要注意。

  1. user_or_group,这个参数是一个User或者Group类型的对象。
  2. 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.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(perm,user_or_group=None, obj=None)

>>> 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函数。

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

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

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

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

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

 该方法是一个用来判断权限的包装器,针对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']

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

 >>> 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一样,我们也需要在界面上进行权限控制以显示不同的界面。

get_obj_perms

{% 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 %}

 孤儿对象许可

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

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

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

 

 $ python manage.py clean_orphan_obj_perms
Removed 11 object permission entries with no targets
该函数会返回删除的对象数目。在python的世界中,我们可以使用celery定期调度这个任务。
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)

 

posted @ 2019-08-30 23:40  逐梦客!  阅读(642)  评论(0)    收藏  举报