In Django, superuser can add more user according to their roll. I'm using simple JWT with DRF for authentication. But it is impossible to detect the type of user only by seeing the Access and Refresh Tokens.
Here are my settings.py file
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_simplejwt.authentication.JWTAuthentication',),
}
urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('Manage_Merchants.urls')),
path('api-auth', include('rest_framework.urls')),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
when I hit on 127.0.0.1:8000/api/token/ through Postman it asks for username and password. When I put Username and Password it generates a Refresh and Access Token. Generate JWT with DRF using Postman
So how can I identify the token is generated for super user or other user created bu superuser? How can I pass more value as a dictionary along with Access and Refresh Tokens to identify the type of user?
JWT, short for JSON Web Token is an open standard for communicating authorization details between server and client. Unlike TokenAuthentication where the token is randomly generated and the authentication details are stored on the server, JWT is self-contained.
In the version djangorestframework-simplejwt==4.4.0
it's the method validate
instead of to_representation
, meaning:
In your serializer.py
you need to override the TokenObtainPairSerializer
in order to include all the data you want to send in the response
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
# The default result (access/refresh tokens)
data = super(CustomTokenObtainPairSerializer, self).validate(attrs)
# Custom data you want to include
data.update({'user': self.user.username})
data.update({'id': self.user.id})
# and everything else you want to send in the response
return data
Now in your views.py
you need to override the TokenObtainPairView in order to pair it with the new serializer.
from .serializers import CustomTokenObtainPairSerializer
class CustomTokenObtainPairView(TokenObtainPairView):
# Replace the serializer with your custom
serializer_class = CustomTokenObtainPairSerializer
Now map your it in your url.py
from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView
from . import views
urlpatterns = [
# This one now has the custom view mapped with the custom serializer that includes the desired data
path('token/', views.CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('token/verify/', TokenVerifyView.as_view(), name='token_verify')
]
Like kumar said, you should override TokenObtainPairView. Let me get deeper in it:
Create a new classView in your core app views.py, or if you want to have a cleaner code, you could create a new app for example called jwt_token_patched and create a views.py file in it. Now add below code to it:
class TokenObtainPairPatchedView(TokenObtainPairView):
"""
Takes a set of user credentials and returns an access and refresh JSON web
token pair to prove the authentication of those credentials.
"""
serializer_class = serializers.TokenObtainPairPatchedSerializer
token_obtain_pair = TokenObtainPairView.as_view()
Now for serializer add this:
class TokenObtainPairPatchedSerializer(TokenObtainPairSerializer):
def to_representation(self, instance):
r = super(TokenObtainPairPatchedSerializer, self).to_representation(instance)
r.update({'user': self.user.username})
return r
method to_representation() is called when serializer is returning data in json format, so you could add anything that you want in there. remember I just put username in user field value, you can add any item value of user that you want in it.
Also create a url for this and from now on use that method for getting token. Feel free to ask any questions if you want. hope it was usefull :)
For customizing refresh token the best thing you can do is override the "TokenRefreshSerializer" which is shown below. However if you want to get any field form the model we have to decode the token to get the UUID of the user. This can be done using token_backend
Note: do make sure you're using "rest_framework_simplejwt" not "djangorestframework-jwt" since it's been deprecated
from rest_framework_simplejwt.serializers import TokenRefreshSerializer
from rest_framework_simplejwt.state import token_backend
class CustomTokenRefreshSerializer(TokenRefreshSerializer):
def validate(self, attrs):
data = super(CustomTokenRefreshSerializer, self).validate(attrs)
decoded_payload = token_backend.decode(data['access'], verify=True)
user_uid=decoded_payload['user_id']
# add filter query
data.update({'custom_field': 'custom_data')})
return data
And then use this serializer as shown below with "CustomTokenRefreshView" which inherits "TokenRefreshView"
from rest_framework_simplejwt.views import TokenRefreshView
class CustomTokenRefreshView(TokenRefreshView):
"""
Custom Refresh token View
"""
serializer_class = CustomTokenRefreshSerializer
And add this in urls
path('api/token/refresh/', CustomTokenRefreshView.as_view(), name='token_refresh'),
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With