Data Mastery
Data Mastery

Reputation: 2095

Django RestAPI - only allow access to users data with JWT Authentication

I have the following API:

Model:

class Todo(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=20, default="")
    text = models.TextField(max_length=450, default="")
    done = models.BooleanField(default=False)

View:

class TodoView(viewsets.ModelViewSet):
    serializer_class = TodoSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        id = self.request.query_params.get("id")
        queryset = Todo.objects.filter(owner__id=id)
        return queryset

Serializer:

class TodoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Todo
        fields = ("id", "owner", "name", "text", "done")

I use rest_framework_simplejwt for my tokens and the following path to receive my token:

path("api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),

This is the token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjE5Mjg4ODAwLCJqdGkiOiJhY2E4MjM5ZGMyZjA0NGE5YWE4NzM3NWZjMDc2NWQ0YSIsInVzZXJfaWQiOjF9.xJ4s971XE0c9iX0Ar1HQSE84u_LbDKLL4iMswYsk2U8

When I decode it on the jwt.io I can see that it contains the user id:

{
  "token_type": "access",
  "exp": 1619288800,
  "jti": "aca8239dc2f044a9aa87375fc0765d4a",
  "user_id": 1
}

A request on http://localhost:8000/todos/?id=1 without the token in my request header does not work (fine!), but with the token, I also can access http://localhost:8000/todos/?id=2 which is of course undesired. I only want access to http://localhost:8000/todos/?id=1 (the coresponding user_id from the payload)

How can I do this?

Upvotes: 0

Views: 838

Answers (1)

ishak O.
ishak O.

Reputation: 191

Change your get_queryset method with this:

def get_queryset(self):
    reque Todo.objects.filter(owner=self.request.user)

Now anyone can access only own Todo records.

Url should like this http://localhost:8000/todos/<id>

Extra: Don't take owner from client. Instead set yourself. Like below.

class TodoSerializer(serializers.ModelSerializer):
    owner = serializers.HiddenField(default=serializers.CurrentUserDefault())

    class Meta:
        model = Todo
        fields = ("id", "owner", "name", "text", "done")

Upvotes: 1

Related Questions