Designing Django Rest Framework role based authorization Designing Django Rest Framework role based authorization django django

Designing Django Rest Framework role based authorization


Sounds like you want some field level security. You might look into using proxy models to give write access to a limited set of fields for the restricted users.

Another option might be to use a custom serializer class which applies readonly to some fields. get_serializer on a ViewSet subclass could be a good place to do the pivot, you should find the current user in self.request.user.


After giving some thought I found two solutions.

The first solution was (instead of dividing the models as I mentioned in the question) declaring different endpoints (URLs) for each type of action that has to happen. Then in each endpoint serializer defining the valid parameters through the fields class variable.

This means that if one role can only update certain fields, I would create a ModelViewSet for this action and in the serializer class related to this ModelViewSet only allow certain parameters.

This solution has many problems and is not quite RESTful. You might end up with dozens of different URLs. In my case, given that the API is not big and the actions were limited that might not have been a problem in the short term, but sure it would have been a problem when the requirements of the application changed.

The second (and chosen) solution was to define a permission/role table in which you define the endpoint where the action has to happen (if you have built your application in the correct way it can just be the ModelViewSet class name), the action to be executed (list, retrieve, create...) the fields of the related model that can be interacted on and the role that can interact with those fields.

I would suggest using dictionaries as the used data structure for the permission table so each permission check is O(1).

Now each time you get a request to that endpoint, a permission check using that table should be done.

I implemented the permission check by overriding the check_permissions() method in the ModelSetView class. Be careful and keep the original check_permissions() functionality in there too.