DRF: best practice to check the user permission inside the object creation method

Hi,

I use Django Rest Framework as a backend API.

I need to implement an access restriction given user roles (RBAC).

I have different roles : {SIMPLE_USER, DEVELOPER, ADMIN}

I want only the users having the ADMIN role to be able to create another user. (ie: use the create_user function). The ADMIN role will also give specific permissions for other object creations/views I will not show here.

I think that it’s more smart to implement the verification inside the create_user function so that wherever I call the create_user function, I am sure that the verification is done.

Here is what I use but I am not sure this is the best solution:

from django.contrib.auth.models import AbstractUser, models, BaseUserManager
from django.core.exceptions import PermissionDenied


class Role(models.Model):
    SIMPLE_USER = 1
    DEVELOPER = 2
    ADMIN = 3
    ROLE_CHOICES = (
        (SIMPLE_USER, 'analyst'),
        (DEVELOPER, 'developer'),
        (ADMIN, 'admin')
    )
    id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, primary_key=True)
    
    def __str__(self):
        return self.get_id_display()


class CustomUserManager(BaseUserManager):
    def create_user(self, username, current_user,
                    roles=None, password=None):
        if Role.ADMIN not in [r.id for r in list(current_user.roles.all())]:
            raise PermissionDenied()
        user = self.model(
            username=username)
        user.set_password(password)
        user.save()
        roles_objs = []
        if roles is not None:
            for r_id in roles:
                r_obj = Role(r_id)
                r_obj.save()
                roles_objs.append(r_obj)
        user.roles.set(roles_objs)
        return user


class CustomUser(AbstractUser):
    roles = models.ManyToManyField(Role)
    objects = CustomUserManager()
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['password']

    class Meta:
        permissions = (
            ('add_user', 'Add user'),
        )

    def __str__(self):
        return self.username

Many thanks for your help, any advice is welcome (I am at the beginning of the project and have to take the good decisions now :slight_smile: )