DanielK
DanielK

Reputation: 267

How can i use custom model permissions to check before displaying a viewset?

I'm quite new to Django rest framework and are struggling to use the custom model permissions to check if a user is allowed to access a certain endpoint.

Whenever trying to access the endpoint i get the "You are not authorized to perform this action" message even though the user is a superuser and/or has been given all app permissions both to the group and/or user.

Models.py

class User(AbstractBaseUser, PermissionsMixin):
    """
    User model which inherits AbstractBaseuser. AbstractBaseUser provides the 
    core implementation of a user model.
    """

    email = models.EmailField(
        _('email address'),
        unique=True,
    )
    ...

    class Meta:
        ...
        permissions = (
            ('has_users_list', 'Can list users'),
        )

Permissions.py

class UserOrGroupPermission(BasePermission):

    def has_permission(self, request, view):

        user_permissions = Permission.objects.filter(user=request.user)
        group_permissions = Permission.objects.filter(group__user=request.user)

        # get required permissions variable from view
        required_permissions_mapping = getattr(view, 'required_permissions', {})
        # determine if the required permissions for the particular request method
        required_permissions = required_permissions_mapping.get(request.method, [])

        if user_permissions or group_permissions in required_permissions:
            return True

Viewsets.py

class UsersListAPIView(generics.ListCreateAPIView):
    queryset = User.objects.all().order_by('id')
    serializer_class = UsersSerializer
    permission_classes = [UserOrGroupPermission]
    required_permissions = {
        'GET': ['has_users_list']
    }

Upvotes: 0

Views: 169

Answers (1)

Ken4scholars
Ken4scholars

Reputation: 6296

Superusers have all permissions implicitly, which means they necessarily do not have these permissions explicitly assigned to them in the Permission table. And so you should use if user.is_superuser to check that he is a superuser. You also some issues on this line

 if user_permissions or group_permissions in required_permissions:

The in operator takes precedence over the or operator, so basically what you're checking is if the user has any permissions at all or the user's group permissions are in the set of required permissions. And also, you're comparing permission objects with a list of permission names.

The following should help:

def has_permission(self, request, view):
    if request.user.is_superuser:
        return True

    user_permissions = set(Permission.objects.filter(user=request.user).values_list('codename', flat=True))
    group_permissions = set(Permission.objects.filter(group__user=request.user).values_list('codename', flat=True))


    # get required permissions variable from view
    required_permissions_mapping = getattr(view, 'required_permissions', {})
    # determine if the required permissions for the particular request method
    required_permissions = set(required_permissions_mapping.get(request.method, []))

    if required_permissions.issubset(user_permissions | group_permissions):
        return True
    return False

It essentially checks if the required permissions are contained in a union of the two sets of permissions

Upvotes: 2

Related Questions