django-role-permissions
django-role-permissions copied to clipboard
Role not working with DRF ViewSet
Hello, I am trying to implement a DRF based application with some object level permissions.
I tired the following simple configuration with not success:
u = User.objects.get(username='user1')
assign_role(u, "test_role")
views.py
class MyObjectViewSet(HasRoleMixin, viewsets.ReadOnlyModelViewSet):
queryset = MyObject.objects.all()
serializer_class = MyObjectSerializer
allowed_roles = ['test_role']
roles.py
class TestRole(AbstractUserRole):
available_permissions = {
'list_my_objects': True,
}
I can successfully login in with user1
, but calling the get API over that view results in a 403 Forbidden error.
What authentication methods did you enable in your application? Can you send an example on how you are making the request (how are you passing credentials)?
I am using Django Knox for token based authentication. So I perform authentication by retrieving a token using the /login
API.
Before testing django-role-permissions
I made sure that token authentication worked as expected. I set the following settings:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',),
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',)
}
to require authentication for each view. Then sending a request to a view with the token worked as expected.
I did not change the requests format (I'm using Postman and saved them there) when testing Roles.
@filipeximenes I think I might have some wrong configuration. I tried the Quick Start guides from the docs with the same roles defined there (Doctor and Nurse) and I always get true when calling has_permission()
:
>>> user= User.objects.get(username='user1')
>>> assign_role(user, 'doctor')
<class 'config.settings.roles.Doctor'>
>>> from rolepermissions.checkers import has_permission
>>> has_permission(user, 'create_medical_record')
True
>>> has_permission(user, 'edit_patient_file')
True
>>> has_permission(user, 'non_existent_perm')
True
I tried several other attempts both with has_permission
and has_role
functions and they always return True
, even if they should not.
I am using a custom user model with no particular customizations at the moment:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
...
To configure django-roles-permissions I included the app in INSTALLED_APPS:
INSTALLED_APPS = [
...
'rolepermissions'
]
as the last entry in the array. Should it be included before some other django app?
I also have in my settings base.py
:
AUTH_USER_MODEL = 'profiles.User'
ROLEPERMISSIONS_MODULE = 'config.settings.roles'
Any idea on what I could be doing wrong? Thank you!!
@StefanoFioravanzo this is really weird. The only thing that comes to mind is if you are using a superuser
:
https://github.com/vintasoftware/django-role-permissions/blob/28924361e689e994e0c3575e18104a1a5abd8de6/rolepermissions/checkers.py#L31-L36
Can you confirm this is not the case?
@filipeximenes Yes, that user was indeed superuser
. My bad, while trying out different options to make django roles work I checked the superuser
flag and then forgot to remove it.
Now the Quick Start guide example works as expected, though I am still getting the 403 error when using the HasRoleMixin
.
One thing I noticed is that request.user
in dispatch
method of HasRoleMixin
returns django.contrib.auth.models.AnonymousUser
, that does not pass the authentication barrier.
But if I send a request to a view that does not extend HasRoleMixin
I get the correct user. In my case the view subclasses viewsets.ReadOnlyModelViewSet
and request.user
in the list
method of ListModelMixin
returns the correct user object.
I think my issue might be outside of the scope of django-role-permissions but I am completely clueless. Do you have any idea of what could cause this?
Very weird. Could you try using a GenericView
instead of a ViewSet
to see what happens?
Hey @filipeximenes , just tried replacing viewsets.ReadOnlyModelViewSet
with generics.ListAPIView
but I get the same behavior
I had a similar issue (or the same issue), and I fixed it by enabling session authentication as well as token authentication. Without digging much into it, my guess is that the HasRoleMixin is trying to access the user via the session information, and getting anonymous user.
I was using django-rest-auth and had a setting REST_SESSION_LOGIN = False
. When I set that to True
(which initiates a session when you log in with a token) everything worked as expected.
I have dig it a bit, IMO the root cause due to HasRoleMixin
use Django HttpRequest
instead of rest_framework.Request
solution:
in the view
class FakeImportView(ModelViewSet):
permission_classes = [GroupAPIGETPermission, ]
# define role permission
class GroupBasePermission(BasePermission):
message = "No group permission"
group_name = ""
def has_permission(self, request, view):
"""
Should simply return, or raise a 403 response.
"""
try:
print(request.user)
request.user.groups.get(name=self.group_name)
except Group.DoesNotExist:
return False
return True
class GroupAPIGETPermission(GroupBasePermission):
"""
Checks to see if a user is in a particular group
"""
group_name = "data_importer"