I am trying to create a REST API and am stuck at user registration: basically I need to have the access token before I register.
This is the view:
cl
Customize the get_queryset method:
def get_queryset(self):
if self.request.user.is_superuser:
return User.objects.all()
else:
return User.objects.filter(id=self.request.user.id)
This way, an authenticated user can only retrieve, modify or delete its own object.
Specify the permission_classes = (AllowAny,)
so an authenticated user can create a new one.
EDIT: further explanation from comments
Customizing the get_queryset method this way means the following:
Yes, non-authenticated users can send the GET request to retrieve the user list but it will be empty because the return User.objects.filter(id=self.request.user.id) ensures that only information about the authenticated user is returned.
The same applies for other methods, if an authenticated user tries to DELETE another user object, a detail: Not found will be returned (because the user it is trying to access is not in the queryset).
Authenticated users can do whatever they want to their user objects.
This is based on @argaen answer and it worked for me:
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer
permission_classes = (AllowAny,)
authentication_classes = (NoAuthentication,)
filter_backends = (filters.DjangoFilterBackend,)
filter_fields = ('id', 'email', 'name')
def get_queryset(self):
user = TokenAuthentication().authenticate(self.request)
if user is not None:
user = user[0]
if user.is_superuser:
return get_user_model().objects.all()
else:
return get_user_model().objects.filter(id=user.id)
return get_user_model().objects.none()
You could utilizing Django REST Framework's ability to define custom permissions. You can specify both a has_permission
and has_object_permission
within a custom class. This will give you the expected behavior of throwing 403s to anon users for everything except posting to the creation endpoint. It might look something like:
class IsAnonCreate(permissions.BasePermission):
def has_permission(self, request, view):
if request.method == "POST" and not request.user.is_authenticated():
return True
elif not request.user.is_authenticated() and request.method != "POST":
return False
elif request.method in permissions.SAFE_METHODS:
return True
return False
def has_object_permission(self, request, view, obj):
if not request.user.is_authenticated():
return False
if request.method in permissions.SAFE_METHODS:
return True
return obj.username == request.user.username
You could then add some custom handling for authenticated users if you wanted.
Then all you need to do is add the permission class to your ModelViewSet
:
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAnonCreate, )