简体   繁体   中英

Django Djoser Token Authentication not working

TLDR: How and where do I get a user's token after logging in and pass it as a header on all subsequent restricted URLs using Django/Djoser?

I'm trying to create a user login/sign up using Djoser. On the backend after logging in, I get the auth token but then when I try to access any other pages (eg /users/me) it says:

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

I looked online and everywhere says I need to pass the authentication token in the header but all the examples I see use Postman or curl and they just copy and paste the token into the header section. But I want to use Django to do it without knowing the token.

I've seen to use token = request.META['HTTP_AUTHORIZATION'] in order to get the token but I'm not sure where to put it because all I've got is

urlpatterns = [
    path('', include('djoser.urls')),
    path('', include('djoser.urls.authtoken')),
]

in my urls.py file and that's supposed to handle everything for me, so I don't have anything in my views.py or models.py

And then to pass the token value as header I've seen to use the Python requests package:

import requests
response = requests.get('https://website.com/id', headers={'Authorization': 'access_token myToken'})

But once again have no idea where to put that.

In my settings.py I have:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'api.apps.ApiConfig',
    'rest_framework',
    'rest_framework.authtoken',
    'frontend.apps.FrontendConfig',
    'register',
    'djoser',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
}

DJOSER = {
    'LOGIN_FIELD': 'username',
    'USER_CREATE_PASSWORD_RETYPE': True,
    'SERIALIZERS': {
        'user_create': 'register.serializers.UserCreateSerializer',
        'user': 'register.serializers.UserCreateSerializer',
    }
}

I've also tried using Basic Authentication but I could never logout for some reason. Is what I'm asking even possible to do from the backend? Or does it have to be handled from the client side? If so, I'm using Reactjs but still am not sure how to go about it.

For each request you'll need to include the Authorization header with the value Token <auth_token_here> .

The standard way about this is to save the auth token within a cookie. Since you are using React you can easily do this with the js-cookie library.

When your user submits the login form, if login is successful your API should return the token to be stored as a cookie.

Then you can make requests with the token that is persisted in the cookie storage.

import requests
response = requests.get('https://website.com/id', headers={'Authorization': 'token myToken'})

replace access_token to token in authorization dict

Try this:

views.py :

from rest_framework_simplejwt.views import TokenObtainPairView
from django.conf import settings

from rest_framework import status
from rest_framework_simplejwt.exceptions import TokenError,\
    InvalidToken
from rest_framework.response import Response

class MyTokenObtainPairView(TokenObtainPairView):
    
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        try:
            serializer.is_valid(raise_exception=True)
        except TokenError as e:
            raise InvalidToken(e.args[0])
           
          # set access token in browser with Httponly cookie.
        res = Response(serializer.validated_data, status=status.HTTP_200_OK)
        access_token = serializer.validated_data['access']
        res.set_cookie("access_token", access_token, max_age=settings.SIMPLE_JWT.get('ACCESS_TOKEN_LIFETIME').total_seconds(),samesite='Lax',secure=False, httponly=True)
        
        return res

urls.py :

from .views import MyTokenObtainPairView

urlpatterns = [
    ......
    path('auth/', include('djoser.urls')),
    # path('auth/', include('djoser.urls.jwt')),
    
    path('auth/api/token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
]

Create authentication.py :

from rest_framework_simplejwt.authentication import JWTAuthentication    
from django.conf import settings

class CookieHandlerJWTAuthentication(JWTAuthentication):
    def authenticate(self, request):
        # If cookie contains access token, put it inside authorization header
        access_token = request.COOKIES.get('access_token')
        if(access_token):
            request.META['HTTP_AUTHORIZATION'] = '{header_type} {access_token}'.format(
                header_type=settings.SIMPLE_JWT['AUTH_HEADER_TYPES'][0], access_token=access_token)

        return super().authenticate(request)

settings.py :

REST_FRAMEWORK = {
    
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'myproject_name.authentication.CookieHandlerJWTAuthentication',
    )
}

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