简体   繁体   中英

Django DRF Token Authentication

I'm having issues with DRF's token based authentication. Following is my landing page code (after login):

@api_view(['GET','POST'],)
def landing(request):
    this_tenant=request.user.tenant
    end=date_first.date.today()
    start=end-date_first.timedelta(days=30)
    sales_daily=sales_day_wise(start, end, this_tenant)
    invoice_value=sales_raised_value(start, end, this_tenant)
    payment_value=sales_collected_value(start, end, this_tenant)
    return render(request,'landing.html', {'sales_daily':json.dumps(sales_daily, cls=DjangoJSONEncoder),\
        'invoice_value':json.dumps(invoice_value, cls=DjangoJSONEncoder), \
        'payment_value':json.dumps(payment_value, cls=DjangoJSONEncoder)})

I was using Django's built-in login view to authenticate and log in a user, then I revised to consider putting token in the header. But that is also not working

This is my login code:

#Redirect authenticated users to landing page
def custom_login(request):
    if request.user.is_authenticated():
        token, created = Token.objects.get_or_create(user=request.user)
        request.session['AUTHORIZATION'] = "TOKEN "+token.key
        return redirect(landing)
    else:
        return login(request)

Following is my DRF settings:

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        # 'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}

Issue is, when I'm logging in and going to the landing page via browser, DRF is not working and I'm getting the following error:

{"detail":"Authentication credentials were not provided."}

The reason is the custom DRF header (AUTHENTICATION = TOEKN XXXXXXXXXX) is not present in the request.

However, if I use Postman and put in the custom header (AUTHENTICATION = TOKEN XXXXXXXXXXXX), then it works.

How do I solve it?

Would this mean I would need a custom header for every view?

And on using DRF Token, does it open up CSRF vulnerability (this question: Django DRF - How to do CSRF validation with token authentication )?

Thanks a lot!!

  • How do I solve it? Would this mean I would need a custom header for every view? TokenAuthentication is used for Single Page App and the token in Request Header needs to be provided by API client(Postman, Javascript or any other client) on each request. In your case, if you want to use Django views you should activate SessionAuthentication. TokenAuthentication and SessionAuthentication can co-exist. One way is to save the token in the cookie in your in custom login view and read it by javascript client.

  • On using DRF Token, does it open up CSRF vulnerability (this question: Django DRF - How to do CSRF validation with token authentication )? Yes. But there are ways to secure the requests. According to DRF documentation "If you use token authentication in production you must ensure that your API is only available over https". Also, make sure set ALLOWED_HOSTS in settings to the domains that you want Django to respond to so the server does not respond to requests with other origins. There other more secure Auths can be used beside TokenAuthentication like JWT that has been mentioned above.

You need to learn the basics first. What is HTTP, what is HTTP headers, what is Django session (it's not an HTTP header and contents of the session doesn't affect the headers), read Django REST Framework documentation on token authentication.

If you want to test your views in browsers, then explicitly allow Django Session authentication in the DRF DEFAULT_AUTHENTICATION_CLASSES configuration variable. It can coexist with token authentication.

You can't make plain web browser append token to the HTTP request unless you're using some plugin like RESTClient, or DHC or REST Easy.

You're adding token to the Django session but you have disabled session authentication in DRF and even if you'd enable it, DRF doesn't read token from Django session because API client has no way to add Token to the Django session. Even if DRF would read Token from Django sessions it would be totally pointless as the client has no control over contents of the session. Session variables are set on the server, not on the client.

REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.IsAuthenticated',
        ],
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.BasicAuthentication',  # enables simple command line authentication
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication',
        )
    }

Adding 'rest_framework.authentication.SessionAuthentication' has solved this issue most of the time.

Alternative

You can use:

'DEFAULT_AUTHENTICATION_CLASSES': (
       'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
   ),

But now, in order to access protected api urls you must include the Authorization: JWT header.

If it works with curl or postman, this indicates it is not an issue with the backend. This is certainly an issue with the client side code. Have you had a look at your request to your REST api? I would recommend that and ensure the token is being passed in the headers and is formatted correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM