The django-rest middleware on steroids.
The guardian is highly flexible middleware for the django-rest class based views.
The current issue with the django-rest permission is that they are applied at class level and hence making it difficult to have seprarate permissions for individual methods. The guardian solves this issue by providing method based authentication.
Some reasons you might want to use Guardian:
- It can be used to authenticate the user
- It can be used to authorize the payload
- Provides method based authentications as well as class based authentication.
- Python (2.x, 3.x)
- Django (1.8+)
- Django REST (3.x)
Install using pip
...
pip install django-rest-guardian
Let's take a look at a quick example of using guardian to build a simple middleware for authenticating user and authorizing payload.
1. User Authentication
Create a Permssion class in your desired file eg: app/permission.py
by inherinting the permission class from guardian module and overriding the guard method
from django_rest_guardian.permission import AuthPermission
# The method gets request as params and need to return True or False depicting whether the user is verified or not.
class UserAuthenticator(AuthPermission):
def guard(self, request):
if request.user_type == 'user':
return True
else:
return False
Let's use this permission in our view layer - app/views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from app.permission import UserAuthenticator
from django_rest_guardian import guardian
class UserView(APIView):
@guardian(UserAuthenticator) # returns 401 if the UserAuthenticator returns False
def get(self, request):
print 'The user is authenticated if you are seeing this message'
return Response({'result': True}, status=status.HTTP_200_OK)
We can also have multiple authenticator classes. So now let's create one more class and pass it to the guardian
app/permission.py
from django_rest_guardian.permission import AuthPermission
class UserAuthenticator(AuthPermission):
def guard(self, request):
if request.user_type == 'user':
return True
else:
return False
class AdminAuthenticator(AuthPermission):
def guard(self, request):
if request.user_type == 'admin':
return True
else:
return False
The guardian uses a logical short circut OR on the both the authenticator class.
app/views.py
class UserView(APIView):
@guardian(UserAuthenticator, AdminAuthenticator) # returns 401 if the UserAuthenticator returns False
def get(self, request):
print 'The user is authenticated if you are seeing this message'
return Response({'result': True}, status=status.HTTP_200_OK)
2. Payload Authorization
The guardian can also be used to to authorize the payload sent by the frontend. Let's assume this is the payload sent by the frontend
{
"id": 5,
"name": "John",
"hobbies": ["Footbal", "Fencing"]
}
Let's verify the payload
app/views.py
class UserView(APIView):
# returns 400 if the payload is invalid
@guardian(id=int, name=unicode, hobbies=list) # we use unicode because python treats the string as unicode for data.
def post(self, request):
print 'The payload is correct if you are seeing this message'
return Response({'result': True}, status=status.HTTP_200_OK)
Guardian also supports validating n-dimensional lists.
What To Write | What Happens |
---|---|
list | simply validates if payload is list |
[] | works same as list |
[ int ] | Validates that a list should contain only integers. * int can be replaced by any acceptable python data type, even list.* |
[[ unicode ]] | Validates that payload should contain two-dimensional list of Strings. |
[[[[[[ int ]]]]]] | This validates for (count-no-of-square-brackets) dimensional list of integers. I think you get the point. |
Guardian also supports validating insides of a dict.
What to Write | What Happens |
---|---|
{ 'id': int } | Checks in the payload that id should be an integer |
{ 'user': {'name': unicode, 'email': unicode }} | Checks that user is a dict which has name as unicode and email as unicode |
{ 'ids': [int] } | Checks that ids is a list of integers. |
1. Both user authentication and payload verification
We can use user auth and payload verification both at the same time
app/views.py
class UserView(APIView):
@guardian(UserAuthenticator, AdminAuthenticator, id=int, name=unicode, hobbies=list)
def post(self, request):
print 'The user is authenticated and the payload is correct if you are seeing this message'
return Response({'result': True}, status=status.HTTP_200_OK)
2. Pass additional parameter with request
We can pass additional parameter with request to views layer
app/permission.py
from django_rest_guardian.permission import AuthPermission
class UserAuthenticator(AuthPermission):
def guard(self, request):
if request.user_type == 'user':
request.user = 'simon' # adding <user> param to request and returning it.
return True
else:
return False
Now we can access this parameter in view layer app/views.py
class UserView(APIView):
@guardian(UserAuthenticator)
def post(self, request):
print request.user # prints 'simon'
return Response({'result': True}, status=status.HTTP_200_OK)
This project is licensed under the MIT License - see the LICENSE file for details