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.