Issue
I am new to Django and I want to add a Middleware for JWT Authentication. I am using Django version 4.2.6 My Middleware code is as follows:
import jwt
from django.http import JsonResponse
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
class TokenMiddleware(MiddlewareMixin):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Check if the request has an "Authorization" header
authorization = request.META.get('HTTP_AUTHORIZATION')
if authorization and authorization.startswith('Bearer '):
token = authorization.split(' ')[1]
jwks_client = jwt.PyJWKClient(settings.JWT_VERIFY_URL)
header = jwt.get_unverified_header(token)
key = jwks_client.get_signing_key(header["kid"]).key
try:
jwt.decode(token, key, [header["alg"]])
except jwt.ExpiredSignatureError:
return JsonResponse({'error': 'Token has expired'}, status=401)
except jwt.DecodeError:
return JsonResponse({'error': 'Token is invalid'}, status=401)
else:
return JsonResponse({'message': 'Authentication Bearer Token is required.'})
response = self.get_response(request)
return response
I have registered my Middleware in settings.py. I have been trying to fix this error but nothing really helped. It triggers when get_response is called. For this code I am getting the following error:
Traceback (most recent call last):
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/views/generic/base.py", line 104, in view
return self.dispatch(request, *args, **kwargs)
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 492, in dispatch
request = self.initialize_request(request, *args, **kwargs)
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 394, in initialize_request
authenticators=self.get_authenticators(),
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 272, in get_authenticators
return [auth() for auth in self.authentication_classes]
File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 272, in <listcomp>
return [auth() for auth in self.authentication_classes]
TypeError: TokenMiddleware.__init__() missing 1 required positional argument: 'get_response'
[14/Oct/2023 14:10:41] "GET /user/ HTTP/1.1" 500 95495
I have registered my Middleware in settings.py in the following way.
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"my_app.middleware.TokenMiddleware",
"corsheaders.middleware.CorsMiddleware",
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'my_app.middleware.TokenMiddleware',
],
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
# Add other renderers as needed
]
# Other DRF settings...
}
Solution
YOu should not use the MiddlewareMixin
, the MiddlewareMixin
is for the old-style middleware, but you are writing this in the new way, so:
class TokenMiddleware: # !L! no MiddlewareMixin
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
authorization = request.META.get('HTTP_AUTHORIZATION')
if authorization and authorization.startswith('Bearer '):
token = authorization.split(' ')[1]
jwks_client = jwt.PyJWKClient(settings.JWT_VERIFY_URL)
header = jwt.get_unverified_header(token)
key = jwks_client.get_signing_key(header['kid']).key
try:
jwt.decode(token, key, [header['alg']])
except jwt.ExpiredSignatureError:
return JsonResponse({'error': 'Token has expired'}, status=401)
except jwt.DecodeError:
return JsonResponse({'error': 'Token is invalid'}, status=401)
else:
return JsonResponse(
{'message': 'Authentication Bearer Token is required.'}
)
return self.get_response(request)
As for the DRF, your TokenMiddleware
is not an authentication class, but likely not necessary here anyway, since it will go through the middleware. You thus remove this from the AUTHENTICATION_CLASSES
:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
# 'my_app.middleware.TokenMiddleware', # 🖘 remove
],
# …
}
Answered By - willeM_ Van Onsem
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.