JWT authentication doesn't work for custom controller in Django

2.3k views Asked by At

I am using the Django Rest Framework in my Python app, and am using JSON Web Token Authentication (DRF JWT) for the api authentication.

My problem comes when I am building a custom controller. I pointed a specific URL to a function in my calculations.py file that I created. Following are how they look.

urls.py

from django.conf.urls import patterns, include, url
from django.contrib import admin
from rest_framework import routers 
from app.serializers import xxxViewSet, yyyViewSet
from app.calculations import getReturns

router  = routers.DefaultRouter()
router.register(r"xxx", xxxViewSet)
router.register(r"yyy", yyyViewSet)

urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^api/auth/token/$', 'rest_framework_jwt.views.obtain_jwt_token'),
url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api-token-verify/', 'rest_framework_jwt.views.verify_jwt_token'),
url(r'^api/', include(router.urls)),
**url(r'^getReturns/', getReturns),**
)

calculations.py

from django.http import HttpResponse
from .models import xxx, yyy, zzz, aaa

def getReturns(request):
    data = request.GET('data')

    **running calculations here on data and giving out response**

    return HttpResponse(response)

serializers.py

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework import routers, serializers, viewsets, permissions
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from .models import xxx, yyy, zzz, aaa

class xxxSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = xxx
        fields = ('id', 'name')

class xxxViewSet(viewsets.ModelViewSet):
    authentication_classes = [SessionAuthentication, BasicAuthentication, JSONWebTokenAuthentication]
    permission_classes = [permissions.IsAuthenticated, permissions.IsAdminUser]
    queryset = xxx.objects.all()
    serializer_class = xxxSerializer

The above serializers.py file contains serializer classes for all my models, and also viewsets for the same. I haven't yet transferred the viewsets into views.py, so that file is empty for now.

Anyway, my calculations.pyis separate from these files, and the function defined in this file is directly being called by the '/getReturns/' URL without going through a view. How do I incorporate the functions defined in my calculations file into a viewset so that my authorization classes are called before the function gets executed?

1

There are 1 answers

6
Withnail On BEST ANSWER

I started doing this in comments and it was too long. Generally, you haven't really provided enough code to assist properly, but here's my crack anyway. It's not obvious which version/implementation of Django JWT you're using (there are a few), how you're authorising your views, or whether your calculations.py file is a view or something else. (If it's something else, I'd authorise in the view, and call it from there.)

Why are you unable to send a POST? Generally, Once you have the token in your front end, you can use from rest_framework.decorators import authentication_classes and @authentication_classes([JSONWebTokenAuthentication,]) wrapper on any function that needs authorisation.

That looks like this:

@authentication_classes([JSONWebTokenAuthentication,])
def function_here(arguments):
    #function does stuff 

How are you passing/trying to send the web token back to the application?

Presumably in CURL your initial auth to get a token looks something like: curl -X POST -d "username=admin&password=abc123 after that you get (if you're using rest_framework_jwt) the token back: {JWTAuthorization: YourTokenHere}.

After that, to return it to DRF protected pages (assuming they're wrapped, as above, or have a similar protection) - you haven't outlined how you're authorisation - then from the docs you do: curl -H "Authorization: JWT <your_token>" http://localhost:8000/protected-url/

If you're generating the call in Angular or similar, then it's the same - you need to pass it in the headers.

Edit: I'd also note you've drastically increased the amount of code here since my original answer. Fundamentally though, you need to check the auth classes you're declaring; the easiest way is as specified above.