Django 权限管理和guardian插件

内置权限管理

Django内置的权限管理, 是一种表权限, 就是可分别配置某管理员用户对某个表的全部数据有没有增删改查4种权限.

图形界面配置权限

之前提到,使用命令行创建超管用户:

python manage.py createsuperuser

这其实是在最普通的用户的基础上将is_superuseris_staffis_active三个属性设为True,在管理界面的首页 › 认证和授权 › 用户可找到用户详情页,会发现超管用户的权限属性如下:

Django 权限管理和guardian插件_第1张图片

Image

并且在用户权限中,超管用户拥有所有可设置的权限(所有模型表的增删改查)。

首页 › 认证和授权 › 用户中可添加用户,并且可以用图形界面配置新用户的权限,以及权限组都可以用图形界面。

Django 权限管理和guardian插件_第2张图片

Image

代码创建用户并配置权限

用代码可以自动、批量创建用户。可以用django-shell, 也可写入文件。 以django-shell为例, 先在项目目录运行django-shell:python manage.py shell, 然后运行:

from django.contrib.auth.models import User
from django.contrib.auth.models import Permission

user = User.objects.create_user( username='jam123', password='12345678', is_staff=True, first_name='jam')

以上代码可创建一个管理员用户, 可以登录后台, 但目前还无任何权限. 权限本身就是多对多关联对象, 配置方法与多对多关联关系一样:

from django.db.models.query_utils import Q
user.user_permissions.add( *Permission.objects.filter( Q(codename__startswith='view')| Q(codename__startswith='delete')))

codename一般写为以add、change、delete、view开头,后接下划线加表名小写,例如add_user__startswith代表以什么字符开头. 所以以上代码可给刚刚创建的用户赋予“查看”和“删除”所有模型表内所有对象的权限.

guardian插件

Django框架的一大特色就是有各种各样强大的插件可以选用。 内置的权限管理只能配置表权限,如果要达到“某个管理员控制某个单独对象”的功能,需要安装使用guardian插件。

安装和准备

在有pip的前提下,在项目目录下执行:

pip install django-guardian

安装好后,需要在项目settings.py文件中指定app,在INSTALLED_APPS中这样添加:

INSTALLED_APPS = [
    
    'guardian',
]

AUTHENTICATION_BACKENDS是指定可以进行权限控制的工具,在其中这样添加:

AUTHENTICATION_BACKENDS = ( 
    'django.contrib.auth.backends.ModelBackend', # 这是Django自带默认的
    'guardian.backends.ObjectPermissionBackend', # 这是guardian的
) 

在admin.py中引入

使用Guardian最直观的特色就是在django-admin页面可以图形化地使用对象权限功能。 首先,在admin.py开头,从guardian添加两个导入:

from guardian.admin import GuardedModelAdminMixin
from guardian.shortcuts import get_objects_for_user, assign_perm

GuardedModelAdminMixin是一个类,包含权限管理的功能,其中Mixin(混入)代表这个类不能单独作为ModelAdmin类使用,需要与其他的ModelAdmin类共同作为子类的父类,新的子类即可既有ModelAdmin的功能也有Guardian权限管理的功能。 但是,GuardedModelAdminMixin本身的功能还是欠缺了点,或者说它本来就是希望开发者自定义重写的。网上有大神将此类继承后重写,完善了其功能,我们将代码抄过来即可(可根据自己项目的特点修改其代码):

class GuardedMixin(GuardedModelAdminMixin):
    # app是否在主页面中显示,由该函数决定
    def has_module_permission(self, request):
        if super().has_module_permission(request):
            return True
        return self.get_model_objs(request,'view').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
        data = get_objects_for_user(
            user=request.user, 
            perms=[f'{perm}_{model_name}' for perm in actions],
            klass=klass, any_perm=True
        )
        if hasattr(request.user, 'teacher'):
            data = teacher.objects.filter(id=request.user.teacher.id) | data
        return data
    # 用来判断某个用户是否有某个数据行的权限
    def has_perm(self, request, obj, action):
        opts = self.opts
        codename = f'{action}_{opts.model_name}'
        if hasattr(request.user, 'teacher') and obj == request.user.teacher:
            return True
        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

当然,这些代码不是尽善尽美的,我们可根据自己项目的特点适当修改这些代码。 而后,将这个我们自己写的GuardedMixin类作为我们自己原来的模型的ModelAdmin类的父类之一:

class TeacherAdmin(GuardedMixin,ModelAdmin):
    # 详情表单页
    inlines = [Class_head_yearInline,FamilyMemberInline]
    fieldsets = [
        # ...

admin.py就编辑完成了,在admin管理页面的Teacher页面中就可以设置某个管理员针对某个teacher对象的权限了。

在图形界面使用

用超级管理员账户,打开某位教师的信息详情页,在右上角出现的“对象权限”按钮,就是我们配置的guardian插件体现的效果。

Django 权限管理和guardian插件_第3张图片

Image

点击它。

Django 权限管理和guardian插件_第4张图片

Image

用户身份写入管理员的名字,点击管理用户,便可设置此管理员针对此对象的权限设置,共有增删改查四种设置。

Django 权限管理和guardian插件_第5张图片

Image

你可能感兴趣的:(django,python,后端)