Reputation: 3475
I was wondering the best way to create a custom permission that checks if a user is in a particular group. Previously, I had a decorator I could use on a view to pass in a tuple of group names along with the user object and then check if that user was in the groups specified.
Ie:
def in_group_views(*group_names):
"""Requires user membership in at least one of the groups passed in."""
def in_groups(u):
if u.is_authenticated():
if bool(u.groups.filter(name__in=group_names)) | u.is_superuser:
return True
return False
return user_passes_test(in_groups)
How would I do this for DRF for a viewset, taking into account I need to check for different group memberships for different actions (POST,PUT,GET) etc.
Many thanks, Ben
Upvotes: 35
Views: 16038
Reputation: 33901
The sensible way to parameterize permission classes is to put the parameters on the view class. That'll let you change the behaviour from view to view.
Here's an example:
# permissions.py
from django.contrib.auth.models import Group
from rest_framework import permissions
def is_in_group(user, group_name):
"""
Takes a user and a group name, and returns `True` if the user is in that group.
"""
try:
return Group.objects.get(name=group_name).user_set.filter(id=user.id).exists()
except Group.DoesNotExist:
return None
class HasGroupPermission(permissions.BasePermission):
"""
Ensure user is in required groups.
"""
def has_permission(self, request, view):
# Get a mapping of methods -> required group.
required_groups_mapping = getattr(view, "required_groups", {})
# Determine the required groups for this particular request method.
required_groups = required_groups_mapping.get(request.method, [])
# Return True if the user has all the required groups or is staff.
return all([is_in_group(request.user, group_name) if group_name != "__all__" else True for group_name in required_groups]) or (request.user and request.user.is_staff)
You could then use the HasGroupPermission
class like so:
# views.py
class MyView(APIView):
permission_classes = [HasGroupPermission]
required_groups = {
'GET': ['moderators', 'members'],
'POST': ['moderators', 'someMadeUpGroup'],
'PUT': ['__all__'],
}
...
Upvotes: 93