Django DRF role level permission - django

I have developed API's using DRF. I am struggling to relate the authorization part from Django's default permission which we define in the admin section for each and every role to the API.
Let's say I have two API's Customer Management and Customer Sales and have two roles created from them at the Django admin portal. manager role will only manage customer (add, view, delete and update) whereas sales role will manage sales (add, view, delete and update) for every customer.
When I try testing them in the admin portal the permissions work fine. The corresponding role has corresponding access. If I use the same with REST API it fails to comply with permission which is defined in the backend. It is like both the roles are able to access both the API's.
How do I handle this? Should I implement my own permission system ignoring old one (auth_permission, auth_group_permissions, auth_user_user_permissions) used in Django or is there any workaround to use Django permissions to make this work?

You can make your permission class as below
class CustomPermission(BasePermission):
def has_permission(self, request, view):
if request.user.is_authenticated():
return True if request.has_perm('can_read') else False # or stuff similar to this
return False
And use this CustomPermission class to your APIView 's attribute.
For more information on DRF permissions visit https://www.django-rest-framework.org/api-guide/permissions/

Related

Create custom permission classes

I have designed my own RBAC system for my Django app. Unlike the original Django's role-based that uses only permissions, content_types, groups, and users table, I designed mine so that it includes a model for defined operations (i.e. read, write, print), the objects (i.e. Post, Events, Documents), the roles (Writer Level 1, Events Manager) and the necessary relationships i.e. my own permissions table which takes in the object reference and a matching operation reference (i.e. Post | add).
My problem now is I am not quite sure how to implement this in DRF. When I use permission_class = (DjangoObjectPermissions,) and someone sends a 'POST' request to the Post model/table, we all know Django will check if the user has Can add post permission. I want to do this as well but I want Django to refer to my RBAC models/tables.
I want to write my own permission classes in my permissions.py but I might need a bit hint on how to implement this.
I've read you can create custom permissions, but I am not sure if that also means you can enforce your own RBAC tables with it.
Alright after checking rest_frameworks' permissions.py, I think I can enforce my own permission class behavior this way:
Create a custom permission class that subclasses rest_framework.permissions.BasePermission
override has_object_permission() method
Inside the method, write a logic that maps the requesting user into my custom RBAC models to check whether or not he has given the appropriate permission
Return the appropriate boolean
According to the DRF Permissions doc
As with DjangoModelPermissions, this permission must only be applied to views that have a .queryset property or .get_queryset() method. Authorization will only be granted if the user is authenticated and has the relevant per-object permissions and relevant model permissions assigned.
So, you should define either queryset attribute or get_queryset(...) method in your view class.
Example:
class MyViewClass(viewsets.ModelViewSet):
queryset = SomeModel.objects.all()
...
...
...
def get_queryset(self):
return SomeModel.objects.filter(some_field='foo')
...
...
...
The permissions to a User or groups can be controlled via Django's Admin site as well as Django shell

I need help in designing a database (and signup and login on base of their role )in which there are three user

I want make sign up and login on the base of their role there admin can add users and approved the request of other two user so that they can login.When user click on the sign up the user see sign up page accorading to their roll and same for login .
Django implements a pretty decent authentication framework inside it, so you already have things such as Users, Groups and Permissions to work on. All of those being managed easily by the admin page.
What you want to do is to assign a set of groups/permissions to a newly created user to determine its role and then build a frontend that manages the different kind of users in terms of templates. If you want an user to have itself validated before start using your page, refer to the is_active attribute of the User object.
Read for more information:
https://docs.djangoproject.com/en/2.2/topics/auth/default/#user-objects

Django: derive permissions from user_type

I am implementing permissions functionality into my webapp. The requirements specified by the customer are that users can perform some actions based on what kind of user they are. The kind of user is defined based on a combination of user_type:user_role. This is the model:
class User(AbstractUser):
usertype = models.IntegerField(choices=UserType.CHOICES, default=UserType.BUYER_USER)
role = models.IntegerField(choices=UserRole.CHOICES, default=UserRole.NORMAL_USER)
For example we can have:
adviser:regular: can manager_orders
adviser:admin: can do what an adviser:regular does and also manage_advisers (this is no django admin, but an admin for advisers!)
(there are more user_type:user_role)
This seems to conflict with the django permission system, which is based on what permission a user has, instead of what kind of user it is.
That is, when using the django permission system I need to define all possible permissions and assign those permissions to the affected user. Instead, with the approach that I am planning, I would need to derive the permission from the user_type:user_role.
Does it make sense to use the django permission system in this context? How can I derive the permission from the user_type:user_role
If you don't want to stick to #ShangWangs approach in the comments, I would recommend taking a look at Django Object Based Permissions.
With this, you are able to grant permissions to users for objects that derive from a super Model you want to apply the permissions to.
Per the Django docs, you can do this with a custom authentication backend:
https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#handling-authorization-in-custom-backends
Any time Django needs to check if a user has a particular permission it will delegate to the auth backend, passing the current user object as an arg. At this point you can check the usertype and role fields and return appropriate boolean value.
example from the docs:
class SettingsBackend(object):
...
def has_perm(self, user_obj, perm, obj=None):
if user_obj.username == settings.ADMIN_LOGIN:
return True
else:
return False
From what you describe in your question you do not need the complication of 'object-level' permissions as mentioned by others (since you don't have unique permissions for each user, they are based on the type and role)

restrict fields according to user permissions in django

I'm building an API using Django rest framework. I have to restrict access to fields (both read or write access) according to the kind of user logged in. How do I go about it ? I'm considering writing separate serializers for different user roles (I will get an access token with every request using which I can authenticate the user, the next step will get me the user's roles, according to which I want to restrict what fields the user can see/edit).
In case you want to give certain users model level permissions to conduct certain actions you can do this with custom permissions like so:
class T21Turma(models.Model):
class Meta:
permissions = (("can_view_boletim", "Can view boletim"),
("can_view_mensalidades", "Can view mensalidades"),)
Then you can either make several serializers and swap them out in the views based on the permissions, or you can modify the fields of the serializer dynamically.

Rolling out own permission app or modifying django permission

I am working on a project which needs a separate admin interface. The django admin interface is for the super super user, there will be companies who will sign up for our app and then they will have their own admin interface. Everything is set and done despite the permission. We want model level permission that's what Django provides.
What I did is:
class CompanyGroup(models.Model):
name = models.CharField(max_length=254)
permissions = models.ManyToManyField(Permissions)
Now this list all the permissions of the site itself. So, Should I start working on my own permission app or I can modify django Permissions to provide object level permissions for only some models.
Thanks
Try one of the several existing 'row level' / 'per object' permissions apps for Django:
http://django-guardian.readthedocs.org/en/v1.2/
http://django-object-permissions.readthedocs.org/en/latest/
...there are probably others, those are just the first two in Google
We are using django-guardian in current project at work, seems fine.
I am assuming that you need to control access to sub-sets of each model's objects, depending on which company the current user belongs to (i.e. you don't want people from Company A to see items from Company B). For this reason you need row level permissions.
You probably also need to limit the permissions of all 'company users' to only certain actions:
You do not need to create a CompanyGroup class.
Instead just enable the admin site, log in as super user and create a django.contrib.auth.models.Group which contains the global permissions applicable to company users.
then ensure when you create any new company user logins that they are added to that Group