3

In Django I have created a system with various groups of users. Using django.auth I have also created permission groups and I have associated the appropriate application permissions for each group.

This works great for role based access, but now I have a requirement where I also need the ability to remove individual permissions from a specific user in a group. This means I need group permissions, but at the same time these group permissions can be unassigned to individual users.

Using Django groups this appears to not directly be possible as the permissions are abstracted from individual users.

How can I accomplish this?

I am in the process of changing everything to individual user permissions, but this seems a bit tedious for clients as they have to manually set permissions for each new user, I am hoping someone knows of a better way.

ViaTech
  • 2,143
  • 1
  • 16
  • 51
  • Yeah, you can assign individual permissions, but it seems you're looking for negative permissions, which I don't believe is supported. You could write an app to implement that feature or you could redefine how the permissions are assigned. After all, group permissions are meant to be "things that all members of this group can do". – Greg Schmit Jun 21 '19 at 22:28

1 Answers1

1

The solution for this only required a ManyToMany field in my User model to hold revoked permissions and custom backend authentication.

User:

revoked_permissions = models.ManyToManyField(Permission, blank=True)

Authentication Backend:

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission


class UsersAuthenticationBackend(ModelBackend):
    def _get_revoked_perms(self, user_obj):
        if user_obj.is_superuser or user_obj.is_admin:
            revoked_perms = Permission.objects.none()
        elif hasattr(user_obj, 'revoked_permissions'):
            revoked_perms = getattr(user_obj, 'revoked_permissions').values_list('content_type__app_label', 'codename')
        else:
            revoked_perms = Permission.objects.none()

        revoked_perms = ["{}.{}".format(perm[0], perm[1]) for perm in revoked_perms]
        return revoked_perms

    def has_perm(self, user_obj, perm, obj=None):
        if not user_obj.is_active:
            return False

        revoked_perms = self._get_revoked_perms(user_obj)
        all_perms = self.get_all_permissions(user_obj)
        allowed_perms = [p for p in all_perms if not p in revoked_perms]

        return perm in allowed_perms

    def has_module_perms(self, user_obj, app_label):
        if not user_obj.is_active:
            return False

        revoked_perms = self._get_revoked_perms(user_obj)
        all_perms = self.get_all_permissions(user_obj)
        allowed_perms = [p for p in all_perms if not p in revoked_perms]

        for perm in allowed_perms:
            if perm[:perm.index('.')] == app_label:
                return True
        return False

Settings.py:

AUTHENTICATION_BACKENDS = [
    "apps.users.backends.UsersAuthenticationBackend"
]

Using this I am now able to set overall group permissions and then also individually revoke permissions for specific users.

ViaTech
  • 2,143
  • 1
  • 16
  • 51