django-rest-knox with cookies

2020-06-23 06:41发布

问题:

I have a question about authentication using django-rest-knox. I want to use cookie storage, not localStorage on client side. So I'm going to implement like below


class LoginView(GenericAPIView):
    serializer_class = LoginSerializer
    permission_classes = (AllowAny,)

    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data
        token = AuthToken.objects.create(user)
        response = Response({
            'user': UserSerializer(user, context=self.get_serializer_context()).data,
            'token': token
        })
        response.set_cookie('token',
                            token,
                            httponly=True)
        return response

Is it correct way to use django-rest-knox? or Do I need to use localStorage? I don't want to use JWT because I saw many negative opinions here.

回答1:

First, thanks for posting this question. I had a similar requirement to not use local storage, and your work got be pointed in the right direction.

Looking at Knox's LoginView implementation (here), it looks like there's a fair amount of logic that isn't replicated in your version (e.g., token count limits).

I took the approach of extending Knox's LoginView. I call the default post method to use Knox's implementation, then strip out the information I don't want to be made available to JS on the client.

from django.contrib.auth import login
from rest_framework import permissions
from rest_framework.authtoken.serializers import AuthTokenSerializer
from knox.views import LoginView as KnoxLoginView


class LoginView(KnoxLoginView):
    permission_classes = (permissions.AllowAny,)

    def post(self, request, format=None):
        serializer = AuthTokenSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)
        response = super(LoginView, self).post(request, format=None)

        token = response.data['token']
        del response.data['token']

        response.set_cookie(
            'auth_token',
            token,
            httponly=True,
            samesite='strict'
        )

        return response