How to Handle 3 level permisions on fields in Djan

2019-05-10 13:12发布

问题:

I am building Django REST as backend and Angular JS as front end.

Now I have permissions systems very advanced as 3 level

class UserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    username = serializers.CharField(max_length=100)
    field1 = serializers.CharField(max_length=100)
    field2 = serializers.CharField(max_length=100)
    field3 = serializers.CharField(max_length=100)
    field4 = serializers.CharField(max_length=100)

Now want permissions on

User Role
view
READ / Write / Update /Delete

There are 10 Roles , 30 views like /user/view1 /user/view2 and then READ or write like

These are on field level permissions like

Field1 can be READ by Manager level on view 1
Field1 can be Edit by Manager level on view 2
Feild1 can be Delete by Admin on View 1

I am confused how can i have that sort of permission model.

回答1:

I typically recommend different serializer classes for these cases, but that limits you to read and write permissions (kind of) and may not completely fit your needs.

You would create a serializer for each permission level. Lets say there are three permission levels: Admin, Manager, Normal user.

class NormalUserSerializer(ModelSerializer):
    email = serializers.EmailField(read_only=True, required=True)
    username = serializers.CharField(max_length=100, read_only=True)

    class Meta:
        fields = ("email", "username", )

class ManagerUserSerializer(NormalUserSerializer):
    email = serializers.EmailField(read_only=False, required=True)
    username = serializers.CharField(max_length=100, read_only=False)

class AdminSerializer(ManagerUserSerializer):
    email = serializers.EmailField(read_only=False, required=False)
    username = serializers.CharField(max_length=100, read_only=False)

This will limit normal users to a read-only view of the fields (read_only is enforced by DRF). For managers, they have the ability to read and write to the fields, but they are not able to clear out the contents of the email field (enforced by required). Admins have the ability to read and write to all of the fields, as well as clear out the contents of the email field.

Your view would then return the correct serializer class in get_serializer_class based on the role of the authenticated user.

class UserViewSet(ModelViewSet):

    def get_serializer_class(self):
        if self.request.user.is_superuser:
            return AdminUserSerializer

        if self.request.user.is_staff:
            return ManagerUserSerializer

        return NormalUserSerializer

The other option is enforcing everything in your validate method, and manually removing fields in the to_native method on the serializer. If you can live with creating a serializer for each role, it is the easiest and (arguably) the most cleanest way of implementing role-based permissions on individual fields in Django REST Framework.



回答2:

I have the exact same problem with a client. I created django-rest-framework-roles to automatically parameterize a given DRF method (e.g: get_queryset, get_serializer_class) over the type of user. This way you don't have to repeatedly type out conditional blocks over the types of users.

I would like to extend the library to handle the more complex permissions problems you are describing. I have these same challenges, e.g: parameterizing over Role and HTTP verb.