-->

How can i make django-rest-framework-jwt return to

2020-05-19 02:47发布

问题:

I have a basic django rest service, which

  1. registers a person and
  2. updates his password.

I want to add jwt authentication on top of it. If I follow the tutorial I would need to add a new url named "api-token-auth" in project's urls.py. But, I don't want to add this new url and want my register call to send a token in response.

Here's my code:

serializers.py

class UserSerializer(serializers.HyperlinkedModelSerializer):
    def create(self, validated_data):
        user = User(
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

    def update(self, instance, validated_data):
        instance.set_password(validated_data['password'])
        instance.save()
        return instance

    class Meta:
        model = User
        fields = ('url', 'username', 'password')
        lookup_field = 'username'
        write_only_fields = ('password',)

views.py

class UserViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows users to be viewed or edited.
    """
    queryset = User.objects.exclude(is_superuser=1)
    serializer_class = UserSerializer
    lookup_field = 'username'
  1. What should be done to achieve this ? should I call api-auth-token inside my serializer's create method ?
  2. How does django-rest-framework-jwt handles multiple authentication tokens and correctly identifies which token belongs to which user ? Especially when it doesn't store tokens in a db.
  3. How can I use this authentication mechanism to limit my user to view/update/delete only his user ?
  4. How can I use this authentication mechanism to do anything in general. For instance if a user wants to write his name to /tmp/abcd.txt. How can I make sure that only authenticated users would be able to do so ?
  5. Are there any potential loopholes in this approach. Should I use the same code if my app is going to store lots of classified data ?

回答1:

Question 1: To create a token that would work with django-rest-framework-jwt you can use a function that looks like:

import jwt
from rest_framework_jwt.utils import jwt_payload_handler

def create_token(user):
    payload = jwt_payload_handler(user)
    token = jwt.encode(payload, settings.SECRET_KEY)
    return token.decode('unicode_escape')

you can add this function to the view and create the token once the user has been registered.

Question 2: JWT tokens do not need to be stored int the database you can read me about how JWT works at http://jwt.io/

Question 3 and 4: To use tokens to limit access to a specific view especially an APIView or one of its subclasses or a view provided by Django Rest framework you need to specify the permission classes for example

from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'status': 'request was permitted'
        }
        return Response(content)

Question 5: One potential loop holes while working with Django Rest Framework is the default permissions that you setup from the settings of your application , if for example you allowAll in the settings it make all the views publicly accessible unless you specifically override the permission classes.



回答2:

Accepted answer has some code that generates token but not shows how to integrate it in serializer/view. Also not sure that manual jwt.encode is good modern way if we already have jwt_encode_handler To do this you can create SerializerMethodField and create token there:

token = serializers.SerializerMethodField()

def get_token(self, obj):
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

    payload = jwt_payload_handler(obj)
    token = jwt_encode_handler(payload)
    return token

Then add token field to Meta.fields. For full example refer here