django开发之django-guardian对象级权限

作者:清一

类别:django   

发布时间:2019/09/02 12:58:03   更新时间:2019/09/02 12:58:03


本文讲述的环境:ubuntu、python3、virtualenv。

参考官网:https://django-guardian.readthedocs.io/

 

为什么要使用django-guardian?就是说,默认的django对权限的控制,是能到model(数据库表)级别,如果要对object(数据库表的一条记录)也进行权限控制,就要用到django-guardian。

事实上,我们不少需求都要用到这个东西。

drf如果要用对象级权限控制,也要用这个东东。

django-guardian实现了对象级权限控制,还和django的modle、DTL、drf、cmd等结合的很好。

 

安装

pip install django-guardian

 

安装后

python manage.py migrate

同步数据库表表:

执行完以后,会创建匿名用户,可以在admin用户里边看到。

Guardian匿名用户与Django匿名用户不同。Django匿名用户在数据库中没有条目,但是Guardian匿名用户也有。

在数据库里,还会出现guardian权限的表:

guardian_groupobjectpermission

guardian_userobjectpermission

权限api

增加权限

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不只一级的话,这地方一定要注意。

user_or_group,这个参数是一个User或者Group类型的对象。

obj,这个参数就是相关的对象了。改参数是可省略的,如果省略则赋予Model权限。

注意:codename一般用默认的,是auth_permission表里边的codename列。

 

示例代码:

 

from guardian.shortcuts import assign

user = User.objects.create(username='liuyong')

assign('app.view_task', user)

【分配model权限】

【一旦赋予模型级的权限,那么所有该模型的对象级别的权限就都有了,所以应该先从对象级别进行设置】

user.has_perm('app.view_task') >>True

【判断是否有mode权限】

 

user = User.objects.get(username='liuyong')

user.user_permissions.clear()

【清理权限】

task = Task.objects.create(summary='Some job', content='')

assign('app.view_task', user, task)

【分配obj权限】

user = User.objects.get(username='liuyong')#刷新缓存

user.has_perm('app.view_task',task)

>>True

【判断是否有obj权限】

user.has_perm('app.view_task')#模型级别的权限还没有

>>False

【判断是否有mode权限】

 

>>> 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

 

查看权限

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')

>>所有可编辑的帖子

 

模板应用

https://blog.csdn.net/scdxmoe/article/details/72678005

 

整合到admin

1、在admin添加对象权限。

https://django-guardian.readthedocs.io/en/stable/userguide/admin-integration.html?highlight=prepopulated_fields

2、在admin登录的用户显示对象权限。



#下边部分的增加,用来在admin页面中显示guarded的权限控制。



# app是否在主页面中显示的话由该函数决定

def has_module_permission(self, request):

    if super().has_module_permission(request):

        return True

    return self.get_model_objs(request).exists()



# 在显示数据列表额时候,哪些数据显示,哪些不显示,由该函数控制

def get_queryset(self, request):

    if request.user.is_superuser:

        return super().get_queryset(request)



    data = self.get_model_objs(request)

    return data



# 内部用来获取某个用户有权限访问的数据行

def get_model_objs(self, request, action=None, klass=None):

    opts = self.opts

    actions = [action] if action else ['view', 'change', 'delete']

    klass = klass if klass else opts.model

    model_name = klass._meta.model_name

    return get_objects_for_user(user=request.user, perms=[f'{perm}_{model_name}' for perm in actions],

                                klass=klass, any_perm=True)



# 用来判断某个用户是否有某个数据行的权限

def has_perm(self, request, obj, action):

    opts = self.opts

    codename = f'{action}_{opts.model_name}'

    if obj:

        return request.user.has_perm(f'{opts.app_label}.{codename}', obj)

    else:

        return self.get_model_objs(request, action).exists()



# 是否有查看某个数据行的权限

def has_view_permission(self, request, obj=None):

    return self.has_perm(request, obj, 'view')



# 是否有修改某个数据行的权限

def has_change_permission(self, request, obj=None):

    return self.has_perm(request, obj, 'change')



# 是否有删除某个数据行的权限

def has_delete_permission(self, request, obj=None):

    return self.has_perm(request, obj, 'delete')



# 用户应该拥有他新增的数据行的所有权限

def save_model(self, request, obj, form, change):

    result = super().save_model(request, obj, form, change)

    if not request.user.is_superuser and not change:

        opts = self.opts

        actions = ['view', 'add', 'change', 'delete']

        [assign_perm(f'{opts.app_label}.{action}_{opts.model_name}', request.user, obj) for action in actions]

    return result

 

admin界面中的使用方法

比如blog的model被改造后,

用admin登录admin页面,

选择某条blog以后,再右上角的历史记录旁边,有对象权限,进行修改。

 

添加权限会出现在表:guardian_userobjectpermission

注意,授权创建文章,guardian_userobjectpermission表会自动出现权限。

 

删除文章后,这个不会自动删除。

文章分类的外键会删除。

 

清理失去对象的权限

如果加上对象级权限,又对对象进行了删除,就要用下边命令清理。

 

django命令:要在env中敲命令。

在env外的命令是:

/home/your_root_path/…/env/bin/python3 /home/your_root_path/… /manage.py clean_orphan_obj_perms


本文属于原创文章,未经许可,任何媒体、公司或个人不得刊发或转载。

本文网址:https://www.pyfield.com/blog/?id=27