Role Based Access Control is an approach to provide restrictive access to users in a system based on their role in the organization. It is a major feature which can make your application access refined and obviously more secure. Django provides authentication and authorization features out of the box that youcan leverage to build a role based access control. Django user authentication has built-in models like User, Group and Permission that can help us get granular access control needed by your application.
Here Are Some Build-In Models:
User Objects: Core of Authentication
This model here stores the actual users in the system. It has basic fields like username, password, email etc. You can extend this class to add more attributes as needed by your application. Django user authentication handles the authentication through session and middlewares. With every request, Django hooks a request object that gives details of the logged in user through request.user. To achieve role-based access control you can use the request.user to authorize the user request to access information.
Groups: Way of Categorizing Users
These are logical groups of users as needed by the system. These groups can be assigned permissions and the users can be assigned to these groups. Django provides a basic view in the admin to create these groups and manage the permissions. The group can be coined as the “role” the user has in the system. Like, a user can be an “admin” and belong to a group called “admin” he/she could be “support” staff and can belong to a group called “support”.
Permission: Granular Access Control
The defined groups control access based on the permissions assigned to each group. Django provides add, edit and change permissions for each model by default. These permissions can be used at the admin view and even in your application. For eg, if you have a model say ‘Blog’.
pub_date = models.DateField()
headline = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User)
Each of these models are registered as ContentType in Django and all of the permissions that Django creates under class Permission has a reference to this ContentType. For the model taken as example these are the permissions that would be created by default:
add_blog : Any User or group that has this permission can add a new blog. change_blog: Any user or group that has this permission can edit the blog. delete_blog: Any user or group that has this permission can delete a blog.
Adding Custom Permissions
Django default permissions are very basic and they may not always suffice to your application’s requirement. Django allows you to add custom permissions and use them like you need. You can use a model meta attribute to add new permissions:
permissions = (
("view_blog", "Can view the blog"),
("can_publish_blog", "Can publish a blog"),
These extra permissions are created along with default permissions when you run manage.py migrate.
How To Use These Permissions
These permission can be assigned to a user directly or to a group which can be assigned to a user. For eg; the group “admin” can be assigned all of these permissions, wherein the “support” group may only have “change_blog” permission. That would mean only an admin user can add or delete a blog. Role based access control would come into play when you check for these permission in your views, templates or APIs.
Permissions can be checked in a view using has a _perm method or a decorator. The User object provides the method has_perm(perm, obj=None), where perm is “.” and returns True if the user has the permission.
You can also use a decorator ‘permission_required(perm, login_url=None, raise_exception=False)’ to check the permission. This decorator also takes permission in the form “.”. In addition to that it also takes a login_url which you use to pass the url to your login/error page. If the user does not have the required permission, then he would be redirected to that url.
from Django.contrib.auth.decorators import permission_required
@permission_required(‘blog.can_publish_blog’, login_url=’/signin/’) def publish_blog(request): …
If you have a class based view then you can use “PermissionRequiredMixin”. You can pass one or multiple permission to permission_required parameter.
from Django.contrib.auth.mixins import PermissionRequiredMixin
class PublishBlog(PermissionRequiredMixin, View): permission_required =blog.can_publish_blog’
The permissions of the logged in user are stored in template variable, You can check for a particular permission within an app.
Level of Access Control: Middleware Vs Decorator
This is the question that most of us ask, “where do I put my permission check, decorator or middleware?”. The answer can be kept straightforward by answering if your access control rule is global or specific to few views. For eg; if you have two access control rules, first that all the users accessing the application must have “view_blog” permission and second that only a user having a permission “can_publish_blog” can publish a blog. In case of latter, you can add the check as a decorator to the”publish_blog” view.
However in case of former, you will put that check in your middleware as it applies to all your URLs, a user who does not have this permission cannot enter your application. Now there is nothing wrong to add it as a decorator, that would still keep the views safe. But adding the decorator to each and every view of your application would be cumbersome and if a new developer forgets to add the decorator to a view he wrote then the rule would be violated. Thus any permission that has to be honored globally should be checked in the middleware.
Django user authentication can be used to achieve complete role-based access control for your application. So leverage as much of these features as you can and deliver delight real quick