When building a web API using DRF, you are directly provided some permissions classes such as AllowAny
or IsAuthenticated
for example.
However, it's possible to write your own permissions if these classes don't work for you.
Problem
According to your needs, you might want to have specific permissions for an authenticated user for example.
Suppose that your system is made of two types of users: simple users that we'll call consumer
and shop owners that we'll call owner
.
An Owner is the admin of a shop. He can for example create products that the consumer can read. The consumer can't create, modify or delete the product
resource and he must be authenticated before accessing the product
resources.
It's definitely intuitive to think about just using the IsAuthenticated
class and move on.🤔
Hum! Let's give a quick look at the code of the IsAuthenticated
class in Django.
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
Note that permissions
in Django work at two levels. The resource level and the object level.
The resource level is handled by has_permission
and the object level is handled by has_object_permission
.
So here's how the IsAuthenticated
class code will normally look.
class IsAuthenticated(BasePermission):
"""
Allows access only to authenticated users.
"""
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
def has_object_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
But because it's already defined at the resource level that the user needs to be authenticated, no need to write the has_object_permission
method.
Well, let's write custom permission for our consumers
and owners
.
Solution
We'll write two different permissions:
ConsumerPermission
OwnerPermission
And here are the classes, subclasses of BasePermission
.
class OwnerPermission(BasePermission):
def has_permission(self, request, view):
if view.basename == "product":
return bool(request.user and request.user.is_authenticated and request.user.is_owner)
return False
def has_object_permission(self, request, view, obj):
# Make sure that an owner can only modify and access its own products
if obj.shop.owner == request.owner:
return True
return False
class ConsumerPermission(BasePermission):
def has_permission(self, request, view):
if view.basename == "product" and request.method in SAFE_METHODS:
return bool(request.user and request.user.is_authenticated and request.user.is_consumer)
return False
The SAFE_METHODS is a list of just read methods ('GET', 'HEAD', 'OPTIONS')
.
And here's how you can write your own custom permissions in Django.🚀
You can learn more about permissions in Django in the following documentation.
Article posted using bloggu.io. Try it for free.