django自带的权限管理Permission用法说明

1. Permission概述

Permission是django自带的一个权限管理模块,它允许我们根据用户角色对view、model、object等进行权限控制,确定哪些用户可以进行哪些操作。在django中,Permission和认证系统Authentication是密切相关的,必须先进行认证,才能进行权限控制,否则django会抛出异常。

Permission在django中广泛应用于admin站点和restframework的APIView中,我们也可以在自己的项目中使用Permission进行权限控制。

2. Permission的实现

在django中,Permission的实现需要通过两个类来完成:

2.1 Permission

Permission类是django自定义权限的基础类,我们可以通过继承Permission类自定义我们需要的权限。Permission类有以下两个方法:

has_permission(self, request, view):该方法应返回一个bool值,确定用户是否有访问该view的权限。

has_object_permission(self, request, view, obj):该方法应返回一个bool值,确定用户是否有访问该obj的权限。

通常,我们会在has_permission方法中检查用户是否有访问该view的权限,如果有,返回True,否则返回False。在has_object_permission方法中,我们通常需要确定用户是否有访问该obj的权限,如果有,返回True,否则返回False。obj参数代表需要进行权限控制的model instance,如果我们没有需要进行obj级别的权限控制,则可以忽略该方法。

2.2 UserPassesTestMixin

UserPassesTestMixin是django提供的一个Mixin类,它重载了dispatch方法,在dispatch方法中进行了has_permission的调用。如果has_permission返回False,则用户被重定向到login页面进行认证。

from django.contrib.auth.mixins import UserPassesTestMixin

from django.urls import reverse_lazy

class MyView(UserPassesTestMixin):

def test_func(self):

return self.request.user.is_authenticated

def handle_no_permission(self):

return redirect(reverse_lazy('login'))

上面的例子中,MyView继承了UserPassesTestMixin类,当请求到达MyView时,test_func方法会被调用,该方法应返回一个bool值。如果返回False,则该请求会被重定向到handle_no_permission方法指定的URL页面进行处理。在上面的例子中,我们将被重定向到login页面。

3. Permission的应用

django自带认证系统Authentication,我们可以通过为用户设置不同的角色,来限制用户访问某些view或者obj。在django中,角色通常是通过Group来进行分配和管理,一个Group可以拥有多个Permission,而一个User可以属于多个Group。因此,我们可以通过为User添加或者删除Group,来改变User的角色和权限。

3.1 django admin站点中的Permission

在admin站点中,我们可以通过为User对象分配不同的Group,来限制User访问admin站点中的各个model和view。在admin.py文件中,我们可以通过以下代码设置admin站点的权限:

from django.contrib import admin

from django.contrib.auth.admin import UserAdmin

from django.contrib.auth.models import User, Group

from django.contrib.auth import get_permission_codename

class MyUserAdmin(UserAdmin):

def get_group_permissions(self, user_obj, obj=None):

"""

Return a queryset of permission strings that this user has through their

groups. This method should be used instead of

``user_obj.group_set.permissions()`` if looking to annotate extra data

onto the permissions. If you're just checking for permissions, use

``user_obj.group_set.permissions`` instead.

"""

permissions = super().get_group_permissions(user_obj, obj=obj)

return permissions.annotate(

name=F('codename'),

app_label=Value('auth'),

namespace=Value('admin'),

content_type=F('group__permissions__content_type'),

codename=F('group__permissions__codename'),

)

def get_queryset(self, request):

qs = super().get_queryset(request)

return qs.annotate(

name=F('username'),

app_label=Value('auth'),

namespace=Value('admin'),

content_type=Value(None, output_field=ContentType),

codename=get_permission_codename('view', User._meta),

)

admin.site.unregister(User)

admin.site.register(User, MyUserAdmin)

通过上面的代码,我们可以在admin站点中为User对象分配Group,并通过Group控制User对象的权限。我们也可以自定义Permission,并将其分配给不同的Group。如果我们想在admin站点中自定义Permission,我们可以在admin.py文件中编写以下代码:

class MyPermission(permissions.BasePermission):

def has_permission(self, request, view):

return True

def has_object_permission(self, request, view, obj):

return True

def __str__(self):

return 'my_permission'

admin.site.register(MyPermission)

在以上代码中,我们自定义了MyPermission,该Permission在has_permission和has_object_permission方法中都返回了True,即所有用户都有my_permission。我们将MyPermission注册到admin站点中,便可以在admin站点中为不同的Group分配该权限。

3.2 rest framework中的Permission

在rest framework中,我们同样可以使用Permission进行权限控制。在APIView中,我们可以通过permission_classes属性设置需要使用的Permission,例如:

class MyView(APIView):

permission_classes = (IsAdminUser,)

以上代码中,我们将IsAdminUser的实例赋值给permission_classes属性,该Permission将只允许admin用户访问该view。

我们也可以在自定义的视图中重载get_permission方法来进行权限控制:

class MyPermission(permissions.BasePermission):

def has_permission(self, request, view):

return True

def has_object_permission(self, request, view, obj):

return True

class MyView(APIView):

def get_permission(self):

return (MyPermission(),)

在以上代码中,我们将MyPermission的实例作为get_permission方法的返回值,该Permission将允许所有用户访问该view。

4. Permission高级设置

在django中,我们可以使用model中的Meta类中的permissions属性定义Permission,使用方法如下:

class Book(models.Model):

name = models.CharField(max_length=128)

author = models.CharField(max_length=128)

class Meta:

permissions = [

('can_view', 'Can View Book'),

('can_edit', 'Can Edit Book'),

]

在以上代码中,我们为Book model定义了两个Permission:can_view和can_edit。Permission的第一个参数是权限编码,第二个参数是权限描述。

如果我们想使用Model中的Permission,在view中可以这样使用:

class MyView(APIView):

def get_queryset(self):

if self.request.user.has_perm('myapp.can_edit'):

return Book.objects.all()

else:

return Book.objects.filter(author=self.request.user.username)

在以上代码中,我们在get_queryset方法中使用了has_perm方法,该方法可用于检查用户是否有某个Permission。

5. 总结

Permission是django自带的一个权限管理工具,它可以用于访问控制、用户身份验证和参数验证等方面。因此,我们需要在django的开发中更加深入地学习和使用Permission,以便在对项目进行维护、升级和扩展时,能够更有效地实现自己的需求。

后端开发标签