A Custom middleware can validate each http request for the set of instructions given in the middleware, before sending back a response. Let us see how we can write a custom Middleware. As an example, we will be implementing a custom Authentication Middleware here.
Django’s out-of-the box Authentication middleware only authenticates requests if the project has made use of the Django provided “User” model or has extended the same. If we have otherwise implemented a model from scratch for the user data, we will have to write a custom middleware for authentication and authorization.
I am implementing this in my twitter clone project, where I have used a custom model for user data. The details of the project can be found in my previous blogpost: Building a Twitter Clone with Django REST Framework – I
First, we will create a file in TUser App. We will call it AuthMiddleware.py. To start off, there are a few basic rules to be followed while defining a Middleware. They are:
- The custom middleware must accept a get_response argument while defining the __init__ method. This is called only once when the web server starts.
- Define the __call__() method. This is called each time a request is made.
- Include the path of the above file in settings.py – in the “Middleware” section
This is how a sample middleware is defined:
#AuthMiddleware.py
from django.contrib.auth.backends import BaseBackend
class AuthMiddleware(BaseBackend):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def CustomMiddleware(self,requst):
#Steps to perform
return True
#settings.py
MIDDLEWARE = [
...
#custom middlewares:
'TUsers.AuthMiddleware.AuthMiddleware'
]
Here’s my version of Custom Authentication Middleware – AuthMiddleware.py
class AuthMiddleware(BaseBackend):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
self.auth(request)
return self.get_response(request)
def auth(self,request):
exclusion_list = ['/signup','/login']
if request.path not in exclusion_list:
try:
urlstr = request.path
user = urlstr.split('/')[1]
token = request.session.get('authtoken').get('token')
payload = jwt.decode(token,settings.AUTH_TOKEN)
userObj = TUser.objects.get(username=user)
if payload.get('username') == userObj.username:
return True
else:
raise PermissionDenied
except (jwt.ExpiredSignature, jwt.DecodeError, jwt.InvalidTokenError) as e:
error = {'Error_code': status.HTTP_403_FORBIDDEN,
'Error_Message': "Token is Invalid/Expired"}
logger.error(e)
raise PermissionDenied(error)
except Exception as e:
error = {'Error_code': status.HTTP_403_FORBIDDEN,
'Error_Message': "Invalid User"}
logger.error(e)
raise PermissionDenied(error)
else:
return True
This middleware will automatically validate each and every request made. In this project, the validation is performed to check if the token that a user obtains while Login is valid. If yes, the API end-point performs its action and returns the intended response. If not, an exception is raised and the access to the API is forbidden.
The complete file is available on github:
https://github.com/shilpavijay/TwitterClone/blob/main/TUsers/AuthMiddleware.py
You can find the complete project code here:
https://github.com/shilpavijay/TwitterClone