Django Rest框架与字段级权限

5

我希望构建一个带有字段级别权限的API。我从数据库表中获取这些权限,但在REST框架中,哪里可以检查用户是否能够对对象的字段执行CRUD操作?

database --- model ---- ModelSerializer ---- ModelViewSet --- browser

在 ModelSerializer 中,我可以在它们到达 viewset 之前删除字段,但默认情况下我无法访问 request.user,因此必须实现该功能,尽管可行,但与其他第三方库(如 django-rest-swagger)不兼容。
还是在 ModelViewset 中?在那里,我可以覆盖 list、create、update 和 destroy 方法,在用户没有权限的情况下删除字段。但这对我的元数据实现不太适用,因为它直接从序列化器中获取元数据。
或者两者都用?例如,在序列化器中通过删除不允许读取的字段,在序列化器获取模型时进行操作,并在传递回序列化器之前在 viewset 中删除不允许写入的内容?
5个回答

8
您可以根据特定请求所需的字段创建不同的序列化程序。然后,您需要在视图中覆盖get_serializer_class()函数,并根据您的逻辑决定序列化程序。
根据DRF文档get_serializer_class()

可以重写以提供动态行为,例如对读取和写入操作使用不同的序列化程序,或者为不同类型的用户提供不同的序列化程序。

例如:
class MyView(..):

    def get_serializer_class(self):
        if self.request.user.is_staff: # check if staff user
            return FullAccountSerializer 
        return BasicAccountSerializer
    ... 

1

DRF文档中有一个关于权限的好部分这里。处理(和检查)它们的好地方是在视图集中。从文档中复制一个示例:

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

如果您想拥有自定义权限检查器,您可以定义自己的,并将 IsAuthenticated 替换为您自己的类。


0
如果您正在使用GenericView,DRF默认将请求对象放入序列化器对象的上下文中。您可以通过以下方式访问用户信息:

self.context['request'].user


0
如果你想要在DRF中实现自定义权限,最好使用ModelViewSet。
from rest_framework import status, viewsets

class MyModelViewsets(viewsets.ModelViewSet):
    queryset = # queryset
    serializer_class = # serializer class
    permission_classes = (# custom permission class her)

如果您想将自定义权限应用于所有端点,请在settings.py中指定它。
REST_FRAMEWORK = {

    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
        # add custom permission here
    ]
}

0
from utils.mixins import MultiSerializerViewSetMixin


class UserViewSet(MultiSerializerViewSetMixin, ModelViewSet):
    serializer_class = UserSerializer
    serializer_action_classes = {
        'update': UserDetailSerializer,
    }
    permission_classes = (UserPermission,)
    queryset = User.objects.all()

MultiSerializerViewSetMixin 的源代码: https://gist.github.com/gonz/10044002

我通过两个序列化程序来解决我的问题:

from django.contrib.auth.models import User
from rest_framework import serializers


class UserSerializerMixin(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    is_superuser = serializers.BooleanField(read_only=True)
    first_name = serializers.CharField(max_length=30, required=False, allow_blank=True)
    last_name = serializers.CharField(max_length=30, required=False, allow_blank=True)
    email = serializers.EmailField(required=False, allow_blank=True)

    def create(self, validated_data):
        return User.objects.create_user(**validated_data)

    def update(self, instance, validated_data):
        instance.first_name = validated_data.get('first_name', instance.first_name)
        instance.last_name = validated_data.get('last_name', instance.last_name)
        instance.email = validated_data.get('email', instance.email)
        password = validated_data.get('password', '')
        if password:
            instance.set_password(password)
            instance.save()
        return instance

    class Meta:
        model = User


class UserSerializer(UserSerializerMixin):
    username = serializers.CharField(max_length=30)
    password = serializers.CharField(
        max_length=128, write_only=True,
        style={'input_type': 'password'})


class UserDetailSerializer(UserSerializerMixin):
    username = serializers.CharField(read_only=True)
    password = serializers.CharField(
        max_length=128, write_only=True,
        style={'input_type': 'password'},
        required=False, allow_blank=True
    )

你可能可以使用MultiSerializerViewSetMixin,我去年在工作中发现了它,并使用mixins创建了两个不同但相似的序列化程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接