Reputation: 7789
I was using Django users model for my Django rest framework. For this I used Django's ModelViewSet for my User class.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
Serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'password']
extra_kwargs = {
'password' : {
'write_only':True,
'required': True
}
}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user) # create token for the user
return user
But currently from postman when I make the request using the token of one user to view, delete, edit other users
http://127.0.0.1:8000/api/users/4/
Its able to edit/delete/view other users. I don't want that to happen and one user can make request on itself only is all I want.
This is my apps urls.py
urls.py
from django.urls import path, include
from .views import ArticleViewSet, UserViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('articles', ArticleViewSet, basename='articles')
router.register('users', UserViewSet, basename = 'users')
urlpatterns = [
path('api/', include(router.urls)),
]
How can I prevent one user from accessing other users when they make GET/POST/PUT/DELETE request.
EDIT 1: After adding the IsOwnerOfObject class as provided in he answers below, now when I am requesting the detail of the user himself, I am getting
Authentication credentials were not provided.
Upvotes: 1
Views: 1712
Reputation: 318
Another all-in-one solution could be to use a queryset filter to directly narrow the queryset results. This will prevent an user to delete other users, but also prevent any unauthorized retrieving or listing as the only accessible data will be the user itself only.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""
The get_queryset function is used to get the queryset of the user data corresponding to the logged in user.
It is called when the view is instantiated, and it returns a list containing this user only.
"""
# after get all products on DB it will be filtered by its owner and return the queryset
owner_queryset = self.queryset.filter(username=self.request.user.username)
return owner_queryset
And this can also be used with other objects to allow retrieving only data related to this user.
Upvotes: 0
Reputation: 7789
Building from Ene's answer, authentication and permission classes needs to be provided.
Create a file named permissions.py.
from rest_framework import permissions
class IsOwnerOfObject(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj == request.user
next add the permission and authentication class to ModelViewSet:
from api.permissions import IsOwnerOfObject
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAuthenticated, IsOwnerOfObject]
authentication_classes = (TokenAuthentication,)
Upvotes: 4
Reputation: 3700
Create a file named permissions.py
.
from rest_framework import permissions
class IsOwnerOfObject(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj == request.user
next add the permission class to you ModelViewSet:
from yourapp.permissions import IsOwnerOfObject
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsOwnerOfObject, <other permission classes you want to use>]
More info here: https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/#object-level-permissions
Upvotes: 3
Reputation: 3740
If you want to disable delete completely (Which is probably correct since if you want to "delete" a User you should deactivate it instead.) Then you can replace your view with this:
from rest_framework import viewsets
from rest_framework import generics
class UserViewSet(
generics.CreateModelMixin,
generics.ListModelMixin,
generics.RetrieveModelMixin,
generics.UpdateModelMixin,
generics.viewsets.GenericViewSet
):
queryset = User.objects.all()
serializer_class = UserSerializer
And then you can use Ene Paul's answer to limit who can edit.
Upvotes: 2